From: drh Date: Mon, 8 Aug 2011 17:18:40 +0000 (+0000) Subject: Add code to actually use the sqlite_stat2.cnt field in the query planner. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fheads%2Fquery-planner-tweaks;p=thirdparty%2Fsqlite.git Add code to actually use the sqlite_stat2.cnt field in the query planner. This changes some plans resulting in a few failures in analyze5.test. FossilOrigin-Name: d1248165e3e02aaf8a2a7872793918b4a9f102a8 --- diff --git a/manifest b/manifest index 9fc5569000..f7d3f27a5e 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index d8fb4d6ec4..55dbefbc99 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -794fde6f918b405ebe47068dea76a2d3f7d97733 \ No newline at end of file +d1248165e3e02aaf8a2a7872793918b4a9f102a8 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 6aa0242e94..62ab9ac100 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -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 *)( diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 882509563b..2842aede05 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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. */ diff --git a/src/where.c b/src/where.c index 70054029a6..67177fe520 100644 --- a/src/where.c +++ b/src/where.c @@ -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=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=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( ipDfltColl; @@ -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;