From b13af4c5dd7a0c9be0e7f2b9b0b57936167938ed Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 3 Sep 2013 14:43:12 +0000 Subject: [PATCH] Fix another problem in stat4 sample selection. FossilOrigin-Name: d59f580904e6e7e90fc0a692a3dd4eeff5942479 --- manifest | 16 ++++----- manifest.uuid | 2 +- src/analyze.c | 90 ++++++++++++++++++++++++++++------------------ test/analyze9.test | 35 +++++++++++++++++- 4 files changed, 98 insertions(+), 45 deletions(-) diff --git a/manifest b/manifest index 99db51e4ea..680f65071a 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 4af698a9c6..549d7b88f6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0303d6bc7112e6f810ae1bd75cafc5ffc51f5212 \ No newline at end of file +d59f580904e6e7e90fc0a692a3dd4eeff5942479 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 89dc84f2c1..99a0a2fd8b 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -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; ianEq[i]>pOld->anEq[i] ) return 1; + if( pNew->anEq[i]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->iColiCol) - || (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->iColiCol ) 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; imxSample; 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->nSamplemxSample - || sampleIsBetter(pBest, &p->a[p->iMin]) - ){ + pBest->anEq[i] = p->current.anEq[i]; + if( p->nSamplemxSample || 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->nSamplemxSample || sampleIsBetter(&p->current, &p->a[p->iMin]) ){ + if( p->nSamplemxSample + || 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); } } diff --git a/test/analyze9.test b/test/analyze9.test index 777e462fdb..604f340bf5 100644 --- a/test/analyze9.test +++ b/test/analyze9.test @@ -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