]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
When estimating the cost of an index scan, factor in the cost savings of
authordrh <drh@noemail.net>
Wed, 27 Jul 2016 18:27:02 +0000 (18:27 +0000)
committerdrh <drh@noemail.net>
Wed, 27 Jul 2016 18:27:02 +0000 (18:27 +0000)
being able to use the index to evaluate some WHERE clause terms without
having to do a table lookup.

FossilOrigin-Name: a59b5622f7cc6e502d71aabc12c053582cd03609

manifest
manifest.uuid
src/expr.c
src/sqliteInt.h
src/where.c

index 7f897eb9543fa8dc04e6f85625fa8d75404f557c..0e15122481e55b00cde3e8e6af9d55266567ecfb 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Ensure\sthat\sthe\ssqlite3_scrub_backup()\sextension\screates\sa\sbackup\sdatabase\sat\sleast\sas\slarge\sas\sindicated\sby\sthe\sdatabase\sheader,\seven\sif\sthe\slast\spage\sof\sthe\sinput\sdatabase\sis\sa\sfree-list\sleaf.
-D 2016-07-26T10:46:21.988
+C When\sestimating\sthe\scost\sof\san\sindex\sscan,\sfactor\sin\sthe\scost\ssavings\sof\nbeing\sable\sto\suse\sthe\sindex\sto\sevaluate\ssome\sWHERE\sclause\sterms\swithout\nhaving\sto\sdo\sa\stable\slookup.
+D 2016-07-27T18:27:02.556
 F Makefile.in 6c20d44f72d4564f11652b26291a214c8367e5db
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a
@@ -337,7 +337,7 @@ F src/ctime.c 61949e83c4c36e37195a8398ebc752780b534d95
 F src/date.c 1cc9fb516ec9932c6fd4d2a0d2f8bc4480145c39
 F src/dbstat.c 4f6f7f52b49beb9636ffbd517cfe44a402ba4ad0
 F src/delete.c 4aba4214a377ce8ddde2d2e609777bcc8235200f
-F src/expr.c 21b153e1046c624e9387a17d3261f69b461e700c
+F src/expr.c 3347e66d4e27ec5f3ec7573b9a5f899bbd7d1df8
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c bc4145347595b7770f9a598cff1c848302cf5413
 F src/func.c 61a4114cf7004f10c542cfabbab9f2bcb9033045
@@ -388,7 +388,7 @@ F src/shell.c 9351fc6de11e1d908648c0a92d85627138e3dee5
 F src/sqlite.h.in c6e68a4a47610631822a4f8f83a44c9f75339331
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 46f300b6e300e0fa916d7d58c44b53415b8471a9
-F src/sqliteInt.h 49081ceab08eda9943d555aee57392c5b35d1c60
+F src/sqliteInt.h d25c18c1272a7811e2569c39bfc2fca96156eead
 F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
 F src/status.c 5b18f9526900f61189ab0b83f1ef41d9f871a2ab
 F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
@@ -463,7 +463,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
 F src/wal.c 02eeecc265f6ffd0597378f5d8ae9070b62a406a
 F src/wal.h 6dd221ed384afdc204bc61e25c23ef7fd5a511f2
 F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
-F src/where.c 48eed8ebe319c6cbc7bf7682018f32af0f5189f5
+F src/where.c 7e4d676b5ac4434e5f93606a744d396dc40d9977
 F src/whereInt.h e5b939701a7ceffc5a3a8188a37f9746416ebcd0
 F src/wherecode.c 99707d11907c71d289ee9553d2d1a22f1fd8ba41
 F src/whereexpr.c d7dcbf14ce1b5876c1f76496162c30fcba669563
@@ -1507,7 +1507,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P c0e7d98ef2a13ede5ae865083ede1aaffdf43310
-R 783c6677056c1c6297ef166e24fadbce
-U dan
-Z 42a389186c57610d077ea553714cade1
+P 483994a54dee3c7a3801e0e9d3c96fa9dbd8d2fd
+R 9e4bd013f5c2cf2171d472668aed0d1c
+T *branch * improved-index-scan
+T *sym-improved-index-scan *
+T -sym-trunk *
+U drh
+Z 8f3398744130761f466da0e8b7212fe4
index 1e810448d248a53d16d378766e4162a2e9bba33d..6da37e4d78a44076dba5b7d71103ea6c69709007 100644 (file)
@@ -1 +1 @@
-483994a54dee3c7a3801e0e9d3c96fa9dbd8d2fd
\ No newline at end of file
+a59b5622f7cc6e502d71aabc12c053582cd03609
\ No newline at end of file
index ea52d6625345b6aaa5589a7b41b3f1f3995b521c..c027cf02a4c99a9ebd175b472f84750b95ae31e1 100644 (file)
@@ -3965,6 +3965,61 @@ int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){
   return 0;
 }
 
+/*
+** An instance of the following structure is used by the tree walker
+** to determine if an expression can be evaluated by reference to the
+** index only, without having to do a search for the corresponding
+** table entry.  The IdxCover.pIdx field is the index.  IdxCover.iCur
+** is the cursor for the table.
+*/
+struct IdxCover {
+  Index *pIdx;     /* The index to be tested for coverage */
+  int iCur;        /* Cursor number for the table corresponding to the index */
+};
+
+/*
+** Check to see if there are references to columns in table 
+** pWalker->u.pIdxCover->iCur can be satisfied using the index
+** pWalker->u.pIdxCover->pIdx.
+*/
+static int exprIdxCover(Walker *pWalker, Expr *pExpr){
+  if( pExpr->op==TK_COLUMN
+   && pExpr->iTable==pWalker->u.pIdxCover->iCur
+   && sqlite3ColumnOfIndex(pWalker->u.pIdxCover->pIdx, pExpr->iColumn)<0
+  ){
+    pWalker->eCode = 1;
+    return WRC_Abort;
+  }
+  return WRC_Continue;
+}
+
+/*
+** Determine if an index on table iCur that contains the columns in
+** Bitmask m will cover the expression pExpr.  Return true if the index
+** does cover the expression and false if the expression references
+** table columns that are not found in the index.
+**
+** An index covering an expression means that the expression can be
+** evaluated using only the index and without having to lookup the
+** corresponding table entry.
+*/
+int sqlite3ExprCoveredByIndex(
+  Expr *pExpr,        /* The index to be tested */
+  int iCur,           /* The cursor number for the corresponding table */
+  Index *pIdx         /* The index that might be used for coverage */
+){
+  Walker w;
+  struct IdxCover xcov;
+  memset(&w, 0, sizeof(w));
+  xcov.iCur = iCur;
+  xcov.pIdx = pIdx;
+  w.xExprCallback = exprIdxCover;
+  w.u.pIdxCover = &xcov;
+  sqlite3WalkExpr(&w, pExpr);
+  return !w.eCode;
+}
+
+
 /*
 ** An instance of the following structure is used by the tree walker
 ** to count references to table columns in the arguments of an 
index 879e6703ca59f56a539cf328479e058254a9c17d..c5b1eccc039ddae00c1fb060f6cafbc436f912dd 100644 (file)
@@ -3257,6 +3257,7 @@ struct Walker {
     struct SrcCount *pSrcCount;                /* Counting column references */
     struct CCurHint *pCCurHint;                /* Used by codeCursorHint() */
     int *aiCol;                                /* array of column indexes */
+    struct IdxCover *pIdxCover;                /* Check for index coverage */
   } u;
 };
 
@@ -3700,6 +3701,7 @@ int sqlite3ExprListCompare(ExprList*, ExprList*, int);
 int sqlite3ExprImpliesExpr(Expr*, Expr*, int);
 void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
 void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
+int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx);
 int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
 Vdbe *sqlite3GetVdbe(Parse*);
 #ifndef SQLITE_OMIT_BUILTIN_TEST
index a65f30968e180ede20115e2c1bee2ed67a9ed5b9..6a025749218d823210c311b7639950f3bf0ed6a2 100644 (file)
@@ -2775,11 +2775,34 @@ static int whereLoopAddBtree(
 
         /* The cost of visiting the index rows is N*K, where K is
         ** between 1.1 and 3.0, depending on the relative sizes of the
-        ** index and table rows. If this is a non-covering index scan,
-        ** also add the cost of visiting table rows (N*3.0).  */
+        ** index and table rows. */
         pNew->rRun = rSize + 1 + (15*pProbe->szIdxRow)/pTab->szTabRow;
         if( m!=0 ){
-          pNew->rRun = sqlite3LogEstAdd(pNew->rRun, rSize+16);
+          /* If this is a non-covering index scan, add in the cost of
+          ** doing table lookups.  The cost will be 3x the number of
+          ** lookups.  Take into account WHERE clause terms that can be
+          ** satisfied using just the index, and that do not require a
+          ** table lookup. */
+          LogEst nLookup = rSize + 16;  /* Base cost:  N*3 */
+          int ii;
+          int iCur = pSrc->iCursor;
+          WhereClause *pWC = &pWInfo->sWC;
+          for(ii=0; ii<pWC->nTerm; ii++){
+            WhereTerm *pTerm = &pWC->a[ii];
+            if( !sqlite3ExprCoveredByIndex(pTerm->pExpr, iCur, pProbe) ){
+              break;
+            }
+            /* pTerm can be evaluated using just the index.  So reduce
+            ** the expected number of table lookups accordingly */
+            if( pTerm->truthProb<=0 ){
+              nLookup += pTerm->truthProb;
+            }else{
+              nLookup--;
+              if( pTerm->eOperator & (WO_EQ|WO_IS) ) nLookup -= 19;
+            }
+          }
+          
+          pNew->rRun = sqlite3LogEstAdd(pNew->rRun, nLookup);
         }
         ApplyCostMultiplier(pNew->rRun, pTab->costMult);
         whereLoopOutputAdjust(pWC, pNew, rSize);