]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add code to actually use the sqlite_stat2.cnt field in the query planner. query-planner-tweaks
authordrh <drh@noemail.net>
Mon, 8 Aug 2011 17:18:40 +0000 (17:18 +0000)
committerdrh <drh@noemail.net>
Mon, 8 Aug 2011 17:18:40 +0000 (17:18 +0000)
This changes some plans resulting in a few failures in analyze5.test.

FossilOrigin-Name: d1248165e3e02aaf8a2a7872793918b4a9f102a8

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

index 9fc556900041eb322b7a39c04c9b341c79c0b246..f7d3f27a5e363d89365465aeeecea3ff39929e1f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C The\sANALYZE\scommand\sadds\sthe\ssqlite_stat2.cnt\scolumn\sif\sit\sdoes\snot\salready\nexist.
-D 2011-08-07T00:21:17.038
+C Add\scode\sto\sactually\suse\sthe\ssqlite_stat2.cnt\sfield\sin\sthe\squery\splanner.\nThis\schanges\ssome\splans\sresulting\sin\sa\sfew\sfailures\sin\sanalyze5.test.
+D 2011-08-08T17:18:40.515
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 1e6988b3c11dee9bd5edc0c804bd4468d74a9cdc
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -118,7 +118,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
 F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
 F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
 F src/alter.c ac80a0f31189f8b4a524ebf661e47e84536ee7f5
-F src/analyze.c ab43a0dea4df603b644a0bc883aeea47856169a6
+F src/analyze.c dcdbff4a23afef0983c4a6fb049cceca905e38a5
 F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f
 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
 F src/backup.c 986c15232757f2873dff35ee3b35cbf935fc573c
@@ -183,7 +183,7 @@ F src/select.c d219c4b68d603cc734b6f9b1e2780fee12a1fa0d
 F src/shell.c bbe7818ff5bc8614105ceb81ad67b8bdc0b671dd
 F src/sqlite.h.in 0b3cab7b2ea51f58396e8871fa5f349cfece5330
 F src/sqlite3ext.h 1a1a4f784aa9c3b00edd287940197de52487cd93
-F src/sqliteInt.h a01882eb98520566f039017232290dde2d0cbeed
+F src/sqliteInt.h fefed2b4717d42c6637285ff4f339c5c648ed5c4
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -250,7 +250,7 @@ F src/vtab.c 901791a47318c0562cd0c676a2c6ff1bc530e582
 F src/wal.c 3154756177d6219e233d84291d5b05f4e06ff5e9
 F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a
 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
-F src/where.c 67ad221f87aa1b12123444cfd9b338e91a50ed7a
+F src/where.c 67c87af7047a913e88fc755aa4de5412af82a3e8
 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
@@ -956,7 +956,7 @@ F tool/symbols.sh caaf6ccc7300fd43353318b44524853e222557d5
 F tool/tostr.awk 11760e1b94a5d3dcd42378f3cc18544c06cfa576
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings.sh 2ebae31e1eb352696f3c2f7706a34c084b28c262
-P 6d1e2372fe73f4c04561108aac6bc8c95f6e7a1a
-R bbffc4c86ec6cf77283985eee0cedc8e
+P 794fde6f918b405ebe47068dea76a2d3f7d97733
+R 5323b0a6bd81040b68da13fcd743d5fd
 U drh
-Z 16b3ea4435ed857a5ccfcdb15256b70e
+Z 22bc19a9fa3fe23c4b6a155fd0f36f68
index d8fb4d6ec49c147702e9a1a0e2acff0f8257af49..55dbefbc99df459435d2aa336445d6bc33a5f401 100644 (file)
@@ -1 +1 @@
-794fde6f918b405ebe47068dea76a2d3f7d97733
\ No newline at end of file
+d1248165e3e02aaf8a2a7872793918b4a9f102a8
\ No newline at end of file
index 6aa0242e945ff8a046950763fcefd409ce0fbc35..62ab9ac10096a2f6c6a14b0dc671dda48ba67778 100644 (file)
@@ -839,8 +839,10 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){
         if( pSample==0 ) break;
         eType = sqlite3_column_type(pStmt, 2);
         pSample->eType = (u8)eType;
-        pSample->nCopy = sqlite3_column_int(pStmt, 4);
-        if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+        pSample->nCopy = sqlite3_column_int(pStmt, 3);
+        if( eType==SQLITE_INTEGER ){
+          pSample->u.i = sqlite3_column_int64(pStmt, 2);
+        }else if( eType==SQLITE_FLOAT ){
           pSample->u.r = sqlite3_column_double(pStmt, 2);
         }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
           const char *z = (const char *)(
index 882509563b0d61ada4934b115ce4914641045788..2842aede0523a037dfb0ef427fb461241009ae48 100644 (file)
@@ -1458,7 +1458,8 @@ struct UnpackedRecord {
 struct IndexSample {
   union {
     char *z;        /* Value if eType is SQLITE_TEXT or SQLITE_BLOB */
-    double r;       /* Value if eType is SQLITE_FLOAT or SQLITE_INTEGER */
+    double r;       /* Value if eType is SQLITE_FLOAT */
+    i64 i;          /* Value if eType is SQLITE_INTEGER */
   } u;
   u8 eType;         /* SQLITE_NULL, SQLITE_INTEGER ... etc. */
   u8 nByte;         /* Size in byte of text or blob. */
index 70054029a676ca08c6a9ae8d57bebd5e532e7e91..67177fe52029c99d376e7a52fb06b374c35b751c 100644 (file)
@@ -2422,13 +2422,17 @@ static void bestVirtualIndex(
 
 /*
 ** Argument pIdx is a pointer to an index structure that has an array of
-** pIdx->sample.n evenly spaced samples of the first indexed column
-** stored in Index.sample. These samples divide the domain of values stored
-** the index into (pIdx->sample.n+1) regions.
-** Region 0 contains all values less than the first sample value. Region
-** 1 contains values between the first and second samples.  Region 2 contains
-** values between samples 2 and 3.  And so on.  Region pIdx->sample.n
-** contains values larger than the last sample.
+** pIdx->sample.n (hereafter "S") evenly spaced samples of the first indexed
+** column stored in Index.sample. These samples divide the domain of values
+** stored the index into S+1 regions.  Region 0 contains all values less than
+** the first sample value. Region 1 contains values between the first and
+** second samples.  Region 2 contains values between samples 2 and 3.  And so
+** on.  Region S contains values larger than the last sample.
+**
+** Note that samples are computed as being centered on S buckets where each
+** bucket contains the nearly same number of rows.  This routine takes samples
+** to be dividers between regions, though.  Hence, region 0 and region S
+** contain half as many rows as the interior regions.
 **
 ** If the index contains many duplicates of a single value, then it is
 ** possible that two or more adjacent samples can hold the same value.
@@ -2438,7 +2442,7 @@ static void bestVirtualIndex(
 **
 ** If successful, this function determines which of the regions value 
 ** pVal lies in, sets *piRegion to the region index (a value between 0
-** and S+1, inclusive) and returns SQLITE_OK.
+** and S, inclusive) and returns SQLITE_OK.
 ** Or, if an OOM occurs while converting text values between encodings,
 ** SQLITE_NOMEM is returned and *piRegion is undefined.
 */
@@ -2448,7 +2452,8 @@ static int whereRangeRegion(
   Index *pIdx,                /* Index to consider domain of */
   sqlite3_value *pVal,        /* Value to consider */
   int roundUp,                /* Return largest valid region if true */
-  int *piRegion               /* OUT: Region of domain in which value lies */
+  int *piRegion,              /* OUT: Region of domain in which value lies */
+  u32 *pnCopy                 /* OUT: Number of rows with pVal, or -1 if unk */
 ){
   assert( roundUp==0 || roundUp==1 );
   if( ALWAYS(pVal) ){
@@ -2458,11 +2463,24 @@ static int whereRangeRegion(
     int eType = sqlite3_value_type(pVal);
 
     assert( nSample>0 );
-    if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+    if( eType==SQLITE_INTEGER ){
+      i64 x = sqlite3_value_int64(pVal);
+      for(i=0; i<nSample; i++){
+        if( aSample[i].eType==SQLITE_NULL ) continue;
+        if( aSample[i].eType>=SQLITE_TEXT ) break;
+        if( aSample[i].u.i==x ) *pnCopy = aSample[i].nCopy;
+        if( roundUp ){
+          if( aSample[i].u.i>x ) break;
+        }else{
+          if( aSample[i].u.i>=x ) break;
+        }
+      }
+    }else if( eType==SQLITE_FLOAT ){
       double r = sqlite3_value_double(pVal);
       for(i=0; i<nSample; i++){
         if( aSample[i].eType==SQLITE_NULL ) continue;
         if( aSample[i].eType>=SQLITE_TEXT ) break;
+        if( aSample[i].u.r==r ) *pnCopy = aSample[i].nCopy;
         if( roundUp ){
           if( aSample[i].u.r>r ) break;
         }else{
@@ -2471,6 +2489,7 @@ static int whereRangeRegion(
       }
     }else if( eType==SQLITE_NULL ){
       i = 0;
+      if( aSample[0].eType==SQLITE_NULL ) *pnCopy = aSample[0].nCopy;
       if( roundUp ){
         while( i<nSample && aSample[i].eType==SQLITE_NULL ) i++;
       }
@@ -2480,9 +2499,7 @@ static int whereRangeRegion(
       const u8 *z;
       int n;
 
-      /* pVal comes from sqlite3ValueFromExpr() so the type cannot be NULL */
       assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
-
       if( eType==SQLITE_BLOB ){
         z = (const u8 *)sqlite3_value_blob(pVal);
         pColl = db->pDfltColl;
@@ -2524,6 +2541,7 @@ static int whereRangeRegion(
         {
           c = pColl->xCmp(pColl->pUser, aSample[i].nByte, aSample[i].u.z, n, z);
         }
+        if( c==0 ) *pnCopy = aSample[i].nCopy;
         if( c-roundUp>=0 ) break;
       }
     }
@@ -2632,6 +2650,7 @@ static int whereRangeScanEst(
     int iUpper = p->sample.n;
     int roundUpUpper = 0;
     int roundUpLower = 0;
+    u32 nC = 0;
     u8 aff = p->pTable->aCol[p->aiColumn[0]].affinity;
 
     if( pLower ){
@@ -2652,19 +2671,18 @@ static int whereRangeScanEst(
       sqlite3ValueFree(pUpperVal);
       goto range_est_fallback;
     }else if( pLowerVal==0 ){
-      rc = whereRangeRegion(pParse, p, pUpperVal, roundUpUpper, &iUpper);
+      rc = whereRangeRegion(pParse, p, pUpperVal, roundUpUpper, &iUpper, &nC);
       if( pLower ) iLower = iUpper/2;
     }else if( pUpperVal==0 ){
-      rc = whereRangeRegion(pParse, p, pLowerVal, roundUpLower, &iLower);
+      rc = whereRangeRegion(pParse, p, pLowerVal, roundUpLower, &iLower, &nC);
       if( pUpper ) iUpper = (iLower + p->sample.n + 1)/2;
     }else{
-      rc = whereRangeRegion(pParse, p, pUpperVal, roundUpUpper, &iUpper);
+      rc = whereRangeRegion(pParse, p, pUpperVal, roundUpUpper, &iUpper, &nC);
       if( rc==SQLITE_OK ){
-        rc = whereRangeRegion(pParse, p, pLowerVal, roundUpLower, &iLower);
+        rc = whereRangeRegion(pParse, p, pLowerVal, roundUpLower, &iLower, &nC);
       }
     }
     WHERETRACE(("range scan regions: %d..%d\n", iLower, iUpper));
-
     iEst = iUpper - iLower;
     testcase( iEst==nSample );
     assert( iEst<=nSample );
@@ -2720,6 +2738,7 @@ static int whereEqualScanEst(
   u8 aff;                   /* Column affinity */
   int rc;                   /* Subfunction return code */
   double nRowEst;           /* New estimate of the number of rows */
+  u32 nC = 0;               /* Key copy count */
 
   assert( p->sample.a!=0 );
   assert( p->sample.n>0 );
@@ -2731,17 +2750,24 @@ static int whereEqualScanEst(
     pRhs = sqlite3ValueNew(pParse->db);
   }
   if( pRhs==0 ) return SQLITE_NOTFOUND;
-  rc = whereRangeRegion(pParse, p, pRhs, 0, &iLower);
-  if( rc ) goto whereEqualScanEst_cancel;
-  rc = whereRangeRegion(pParse, p, pRhs, 1, &iUpper);
+  rc = whereRangeRegion(pParse, p, pRhs, 0, &iLower, &nC);
   if( rc ) goto whereEqualScanEst_cancel;
-  WHERETRACE(("equality scan regions: %d..%d\n", iLower, iUpper));
-  if( iLower>=iUpper ){
-    nRowEst = p->aiRowEst[0]/(p->sample.n*3);
-    if( nRowEst<*pnRow ) *pnRow = nRowEst;
+  if( nC==0 ){
+    rc = whereRangeRegion(pParse, p, pRhs, 1, &iUpper, &nC);
+    if( rc ) goto whereEqualScanEst_cancel;
+  }
+  if( nC ){
+    WHERETRACE(("equality scan count: %u\n", nC));
+    *pnRow = nC;
   }else{
-    nRowEst = (iUpper-iLower)*p->aiRowEst[0]/p->sample.n;
-    *pnRow = nRowEst;
+    WHERETRACE(("equality scan regions: %d..%d\n", iLower, iUpper));
+    if( iLower>=iUpper ){
+      nRowEst = p->aiRowEst[0]/(p->sample.n*3);
+      if( nRowEst<*pnRow ) *pnRow = nRowEst;
+    }else{
+      nRowEst = (iUpper-iLower)*p->aiRowEst[0]/p->sample.n;
+      *pnRow = nRowEst;
+    }
   }
 
 whereEqualScanEst_cancel:
@@ -2782,6 +2808,7 @@ static int whereInScanEst(
   int nSingle = 0;          /* Histogram regions hit by a single value */
   int nNotFound = 0;        /* Count of values that are not constants */
   int i;                             /* Loop counter */
+  u32 nC;                            /* Exact count of rows for a key */
   int nSample = p->sample.n;         /* Number of samples */
   u8 aSpan[SQLITE_MAX_SAMPLES+1];    /* Histogram regions that are spanned */
   u8 aSingle[SQLITE_MAX_SAMPLES+1];  /* Histogram regions hit once */
@@ -2799,9 +2826,9 @@ static int whereInScanEst(
       nNotFound++;
       continue;
     }
-    rc = whereRangeRegion(pParse, p, pVal, 0, &iLower);
+    rc = whereRangeRegion(pParse, p, pVal, 0, &iLower, &nC);
     if( rc ) break;
-    rc = whereRangeRegion(pParse, p, pVal, 1, &iUpper);
+    rc = whereRangeRegion(pParse, p, pVal, 1, &iUpper, &nC);
     if( rc ) break;
     if( iLower>=iUpper ){
       aSingle[iLower] = 1;