]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix problems in estimating the number of rows visited by a range query using sqlite_s...
authordan <dan@noemail.net>
Thu, 8 Aug 2013 19:38:40 +0000 (19:38 +0000)
committerdan <dan@noemail.net>
Thu, 8 Aug 2013 19:38:40 +0000 (19:38 +0000)
FossilOrigin-Name: 9228aaf54dd2700c4f460f94f9c2309407578983

manifest
manifest.uuid
src/where.c

index f1338e178697d90f9cce3f2cc04d2a61f4f4ad81..1d393f93d1570e229e43916f9386636dcfdb0748 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Use\sa\sbinary\ssearch\sinstead\sof\sa\slinear\sscan\swhen\scomparing\sa\ssample\skey\sagainst\sdata\sfrom\sthe\ssqlite_stat4\stable.
-D 2013-08-08T16:17:12.293
+C Fix\sproblems\sin\sestimating\sthe\snumber\sof\srows\svisited\sby\sa\srange\squery\susing\ssqlite_stat4\sdata\swhen\sthe\scolumn\ssubject\sto\sthe\srange\squery\sis\snot\sthe\sleftmost\sof\sthe\sindex.
+D 2013-08-08T19:38:40.828
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -290,7 +290,7 @@ F src/vtab.c 2e8b489db47e20ae36cd247932dc671c9ded0624
 F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73
-F src/where.c 2323663d074a94fa1609d65d7175948d490e560b
+F src/where.c 0e058c33d0f4e2616ecd0996c04f3f1b7e3f7afa
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
@@ -1106,7 +1106,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
-P 9fec3e38287067d60874530300fbeb602958c951
-R 05ac6975552968743dc313f6e2204120
+P e50dc30523210ba12324d5d8379503610f13aa34
+R b712a80bcc08bb0cfbaad8e54099473e
 U dan
-Z 09be040e1ce68baa088fb590dab65772
+Z 6384d8e74fabf5ee0daae5c0c2206cf9
index d8543e7110cae4b33825ee728f3966afd89b1809..944774c90ed2981e415ff4f9b0529540f0d60fec 100644 (file)
@@ -1 +1 @@
-e50dc30523210ba12324d5d8379503610f13aa34
\ No newline at end of file
+9228aaf54dd2700c4f460f94f9c2309407578983
\ No newline at end of file
index a8559bce8674a92103e8d617594a50da94387ceb..cde57a16878a2a76df3fd20aaff421d3ce53f1ad 100644 (file)
@@ -2407,7 +2407,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
 **
 ** Return SQLITE_OK on success.
 */
-static int whereKeyStats(
+static void whereKeyStats(
   Parse *pParse,              /* Database connection */
   Index *pIdx,                /* Index to consider domain of */
   UnpackedRecord *pRec,       /* Vector of values to consider */
@@ -2480,7 +2480,6 @@ static int whereKeyStats(
     }
     aStat[0] = iLower + iGap;
   }
-  return SQLITE_OK;
 }
 #endif /* SQLITE_ENABLE_STAT4 */
 
@@ -2543,41 +2542,76 @@ static int whereRangeScanEst(
    && OptimizationEnabled(pParse->db, SQLITE_Stat3) 
   ){
     UnpackedRecord *pRec = pBuilder->pRec;
-    tRowcnt iLower = 0;
-    tRowcnt iUpper = p->aiRowEst[0];
     tRowcnt a[2];
     u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
+
+    /* Variable iLower will be set to the estimate of the number of rows in 
+    ** the index that are less than the lower bound of the range query. The
+    ** lower bound being the concatenation of $P and $L, where $P is the
+    ** key-prefix formed by the nEq values matched against the nEq left-most
+    ** columns of the index, and $L is the value in pLower.
+    **
+    ** Or, if pLower is NULL or $L cannot be extracted from it (because it
+    ** is not a simple variable or literal value), the lower bound of the
+    ** range is $P. Due to a quirk in the way whereKeyStats() works, even
+    ** if $L is available, whereKeyStats() is called for both ($P) and 
+    ** ($P:$L) and the larger of the two returned values used.
+    **
+    ** Similarly, iUpper is to be set to the estimate of the number of rows
+    ** less than the upper bound of the range query. Where the upper bound
+    ** is either ($P) or ($P:$U). Again, even if $U is available, both values
+    ** of iUpper are requested of whereKeyStats() and the smaller used.
+    */
+    tRowcnt iLower;
+    tRowcnt iUpper;
+
+    /* Determine iLower and iUpper using ($P) only. */
+    if( nEq==0 ){
+      iLower = 0;
+      iUpper = p->aiRowEst[0];
+    }else{
+      /* Note: this call could be optimized away - since the same values must 
+      ** have been requested when testing key $P in whereEqualScanEst().  */
+      whereKeyStats(pParse, p, pRec, 0, a);
+      iLower = a[0];
+      iUpper = a[0] + a[1];
+    }
+
+    /* If possible, improve on the iLower estimate using ($P:$L). */
     if( pLower ){
       int bOk;                    /* True if value is extracted from pExpr */
       Expr *pExpr = pLower->pExpr->pRight;
       assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
       rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
-      if( rc==SQLITE_OK && bOk
-       && whereKeyStats(pParse, p, pRec, 0, a)==SQLITE_OK
-      ){
-        iLower = a[0];
-        if( (pLower->eOperator & WO_GT)!=0 ) iLower += a[1];
+      if( rc==SQLITE_OK && bOk ){
+        tRowcnt iNew;
+        whereKeyStats(pParse, p, pRec, 0, a);
+        iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0);
+        if( iNew>iLower ) iLower = iNew;
       }
     }
-    if( rc==SQLITE_OK && pUpper ){
+
+    /* If possible, improve on the iUpper estimate using ($P:$U). */
+    if( pUpper ){
       int bOk;                    /* True if value is extracted from pExpr */
       Expr *pExpr = pUpper->pExpr->pRight;
       assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
       rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
-      if( rc==SQLITE_OK && bOk
-       && whereKeyStats(pParse, p, pRec, 1, a)==SQLITE_OK
-      ){
-        iUpper = a[0];
-        if( (pUpper->eOperator & WO_LE)!=0 ) iUpper += a[1];
+      if( rc==SQLITE_OK && bOk ){
+        tRowcnt iNew;
+        whereKeyStats(pParse, p, pRec, 1, a);
+        iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0);
+        if( iNew<iUpper ) iUpper = iNew;
       }
     }
+
     pBuilder->pRec = pRec;
     if( rc==SQLITE_OK ){
       WhereCost nNew;
       if( iUpper>iLower ){
         nNew = whereCost(iUpper - iLower);
       }else{
-        nNew = whereCost(2);      /* Small number */
+        nNew = 10;        assert( 10==whereCost(2) );
       }
       if( nNew<nOut ){
         nOut = nNew;
@@ -2662,11 +2696,9 @@ static int whereEqualScanEst(
   if( bOk==0 ) return SQLITE_NOTFOUND;
   pBuilder->nRecValid = nEq;
 
-  rc = whereKeyStats(pParse, p, pRec, 0, a);
-  if( rc==SQLITE_OK ){
-    WHERETRACE(0x100,("equality scan regions: %d\n", (int)a[1]));
-    *pnRow = a[1];
-  }
+  whereKeyStats(pParse, p, pRec, 0, a);
+  WHERETRACE(0x100,("equality scan regions: %d\n", (int)a[1]));
+  *pnRow = a[1];
   
   return rc;
 }