]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix another problem in stat4 sample selection.
authordan <dan@noemail.net>
Tue, 3 Sep 2013 14:43:12 +0000 (14:43 +0000)
committerdan <dan@noemail.net>
Tue, 3 Sep 2013 14:43:12 +0000 (14:43 +0000)
FossilOrigin-Name: d59f580904e6e7e90fc0a692a3dd4eeff5942479

manifest
manifest.uuid
src/analyze.c
test/analyze9.test

index 99db51e4ea0e43c219aa3a806efea8484d0e3507..680f65071a85e48b40fb4e7ed9c8350b8a2f15ec 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Make\ssure\sthe\somit-noop-left-join\soptimization\sis\snot\sapplied\sif\scolumns\nof\sthe\sLEFT\sJOIN\sare\sused\sin\sthe\sORDER\sBY\sclause.\s\s\nTicket\s[be84e357c035]
-D 2013-09-03T14:03:47.008
+C Fix\sanother\sproblem\sin\sstat4\ssample\sselection.
+D 2013-09-03T14:43:12.842
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -157,7 +157,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
 F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
 F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
-F src/analyze.c 66903e3e5a36eee728c0dc1d574e8cb16059210f
+F src/analyze.c 51e6e5d56aaee93465a530d8f9e7a9b69cf9702c
 F src/attach.c fea00cab11c854646a27641a263f5876569a51f9
 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
 F src/backup.c 2f1987981139bd2f6d8c728d64bf09fb387443c3
@@ -308,7 +308,7 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
 F test/analyze6.test 19151da2c4e918905d2081b74ac5c4d47fc850ab
 F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
 F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
-F test/analyze9.test 3b23fc97bcc0f4b5629aacdd8e1aa267114dcc79
+F test/analyze9.test 4a48461d71a7b4a958570c580495a97e842e2700
 F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
 F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
 F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
@@ -1109,7 +1109,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
-P f7079b5365dd6cd8324a4fb23605e81476122ed6
-R ef683c5e75a524283b39e51db1610c55
-U drh
-Z 7e7396aa706179eb8731d96e0b228672
+P 0303d6bc7112e6f810ae1bd75cafc5ffc51f5212
+R ae0a46263eba3c1ef0a78f34bdb8ef01
+U dan
+Z 3daa1eef98d5cdbb101dd3c2f83cf235
index 4af698a9c64ddb5cdfa69c0e2dddfd262c129771..549d7b88f66f9ce395c51a12ef4a0aea63446e43 100644 (file)
@@ -1 +1 @@
-0303d6bc7112e6f810ae1bd75cafc5ffc51f5212
\ No newline at end of file
+d59f580904e6e7e90fc0a692a3dd4eeff5942479
\ No newline at end of file
index 89dc84f2c18ca45756e296c3474b6f19a42957b3..99a0a2fd8b625f9eb5a8c04a08405b400c02426e 100644 (file)
@@ -383,24 +383,63 @@ static const FuncDef statInitFuncdef = {
   0                /* pDestructor */
 };
 
+#ifdef SQLITE_ENABLE_STAT4
+/*
+** pNew and pOld are both candidate non-periodic samples selected for 
+** the same column (pNew->iCol==pOld->iCol). Ignoring this column and 
+** considering only any trailing columns and the sample hash value, this
+** function returns true if sample pNew is to be preferred over pOld.
+** In other words, if we assume that the cardinalities of the selected
+** column for pNew and pOld are equal, is pNew to be preferred over pOld.
+**
+** This function assumes that for each argument sample, the contents of
+** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid. 
+*/
+static int sampleIsBetterPost(
+  Stat4Accum *pAccum, 
+  Stat4Sample *pNew, 
+  Stat4Sample *pOld
+){
+  int nCol = pAccum->nCol;
+  int i;
+  assert( pNew->iCol==pOld->iCol );
+  for(i=pNew->iCol+1; i<nCol; i++){
+    if( pNew->anEq[i]>pOld->anEq[i] ) return 1;
+    if( pNew->anEq[i]<pOld->anEq[i] ) return 0;
+  }
+  if( pNew->iHash>pOld->iHash ) return 1;
+  return 0;
+}
+#endif
+
 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
 /*
 ** Return true if pNew is to be preferred over pOld.
+**
+** This function assumes that for each argument sample, the contents of
+** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid. 
 */
-static int sampleIsBetter(Stat4Sample *pNew, Stat4Sample *pOld){
+static int sampleIsBetter(
+  Stat4Accum *pAccum, 
+  Stat4Sample *pNew, 
+  Stat4Sample *pOld
+){
   tRowcnt nEqNew = pNew->anEq[pNew->iCol];
   tRowcnt nEqOld = pOld->anEq[pOld->iCol];
 
   assert( pOld->isPSample==0 && pNew->isPSample==0 );
   assert( IsStat4 || (pNew->iCol==0 && pOld->iCol==0) );
 
-  if( (nEqNew>nEqOld)
-   || (nEqNew==nEqOld && pNew->iCol<pOld->iCol)
-   || (nEqNew==nEqOld && pNew->iCol==pOld->iCol && pNew->iHash>pOld->iHash)
-  ){
-    return 1;
+  if( (nEqNew>nEqOld) ) return 1;
+#ifdef SQLITE_ENABLE_STAT4
+  if( nEqNew==nEqOld ){
+    if( pNew->iCol<pOld->iCol ) return 1;
+    return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld));
   }
   return 0;
+#else
+  return (nEqNew==nEqOld && pNew->iHash>pOld->iHash);
+#endif
 }
 
 /*
@@ -423,8 +462,6 @@ void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
 static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
   Stat4Sample *pSample;
   int i;
-  i64 iSeq;
-  int iPos;
 
   assert( IsStat4 || nEqZero==0 );
 
@@ -441,8 +478,9 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
       Stat4Sample *pOld = &p->a[i];
       if( pOld->anEq[pNew->iCol]==0 ){
         if( pOld->isPSample ) return;
-        assert( sampleIsBetter(pNew, pOld) );
-        if( pUpgrade==0 || sampleIsBetter(pOld, pUpgrade) ){
+        assert( pOld->iCol>pNew->iCol );
+        assert( sampleIsBetter(p, pNew, pOld) );
+        if( pUpgrade==0 || sampleIsBetter(p, pOld, pUpgrade) ){
           pUpgrade = pOld;
         }
       }
@@ -481,25 +519,6 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
   sampleCopy(p, pSample, pNew);
   p->nSample++;
 
-#if 0
-  iSeq = pNew->anLt[p->nCol-1];
-  for(iPos=p->nSample; iPos>0; iPos--){
-    if( iSeq>p->a[iPos-1].anLt[p->nCol-1] ) break;
-  }
-
-  if( iPos!=p->nSample ){
-    Stat4Sample *pEnd = &p->a[p->nSample];
-    tRowcnt *anEq = pEnd->anEq;
-    tRowcnt *anLt = pEnd->anLt;
-    tRowcnt *anDLt = pEnd->anDLt;
-    memmove(&p->a[iPos], &p->a[iPos+1], (p->nSample-iPos)*sizeof(p->a[0]));
-    pSample->anEq = anEq;
-    pSample->anDLt = anDLt;
-    pSample->anLt = anLt;
-  }
-#endif
-
-
   /* Zero the first nEqZero entries in the anEq[] array. */
   memset(pSample->anEq, 0, sizeof(tRowcnt)*nEqZero);
 
@@ -508,7 +527,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
     int iMin = -1;
     for(i=0; i<p->mxSample; i++){
       if( p->a[i].isPSample ) continue;
-      if( iMin<0 || sampleIsBetter(&p->a[iMin], &p->a[i]) ){
+      if( iMin<0 || sampleIsBetter(p, &p->a[iMin], &p->a[i]) ){
         iMin = i;
       }
     }
@@ -532,9 +551,8 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
   ** into IndexSample.a[] at this point.  */
   for(i=(p->nCol-2); i>=iChng; i--){
     Stat4Sample *pBest = &p->aBest[i];
-    if( p->nSample<p->mxSample
-     || sampleIsBetter(pBest, &p->a[p->iMin])
-    ){
+    pBest->anEq[i] = p->current.anEq[i];
+    if( p->nSample<p->mxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){
       sampleInsert(p, pBest, i);
     }
   }
@@ -561,7 +579,9 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
     }else 
 
     /* Or if it is a non-periodic sample. Add it in this case too. */
-    if( p->nSample<p->mxSample || sampleIsBetter(&p->current, &p->a[p->iMin]) ){
+    if( p->nSample<p->mxSample 
+     || sampleIsBetter(p, &p->current, &p->a[p->iMin]) 
+    ){
       sampleInsert(p, &p->current, 0);
     }
   }
@@ -635,7 +655,7 @@ static void statPush(
     /* Update the aBest[] array. */
     for(i=0; i<(p->nCol-1); i++){
       p->current.iCol = i;
-      if( i>=iChng || sampleIsBetter(&p->current, &p->aBest[i]) ){
+      if( i>=iChng || sampleIsBetterPost(p, &p->current, &p->aBest[i]) ){
         sampleCopy(p, &p->aBest[i], &p->current);
       }
     }
index 777e462fdb38b1958eb61b807fd6bf727156a60e..604f340bf5a8fe98d87160d20a864ce38f32fd28 100644 (file)
@@ -244,7 +244,7 @@ do_execsql_test 4.3 {
     FROM sqlite_stat4
   ORDER BY rowid DESC LIMIT 2;
 } {
-  {2 1 1 1} {295 296 296} {120 122 125} {201 4
+  {2 1 1 1} {295 295 295} {120 121 124} {201 3
   {5 3 1 1} {290 290 292} {119 119 121} {200 1}
 }
 
@@ -916,5 +916,38 @@ ifcapable auth {
   } {1 {not authorized}}
 }
 
+#-------------------------------------------------------------------------
+#
+reset_db
+proc r {args} { expr rand() }
+db func r r
+db func lrange lrange
+do_test 20.1 {
+  execsql {
+    CREATE TABLE t1(a,b,c,d);
+    CREATE INDEX i1 ON t1(a,b,c,d);
+  }
+  for {set i 0} {$i < 16} {incr i} {
+    execsql {
+      INSERT INTO t1 VALUES($i, r(), r(), r());
+      INSERT INTO t1 VALUES($i, $i,  r(), r());
+      INSERT INTO t1 VALUES($i, $i,  $i,  r());
+      INSERT INTO t1 VALUES($i, $i,  $i,  $i);
+      INSERT INTO t1 VALUES($i, $i,  $i,  $i);
+      INSERT INTO t1 VALUES($i, $i,  $i,  r());
+      INSERT INTO t1 VALUES($i, $i,  r(), r());
+      INSERT INTO t1 VALUES($i, r(), r(), r());
+    }
+  }
+} {}
+do_execsql_test 20.2 { ANALYZE }
+for {set i 0} {$i<16} {incr i} {
+    set val "$i $i $i $i"
+    do_execsql_test 20.3.$i {
+      SELECT count(*) FROM sqlite_stat4 
+      WHERE lrange(test_decode(sample), 0, 3)=$val
+    } {1}
+}
+
 finish_test