From: dan Date: Thu, 8 Aug 2013 19:38:40 +0000 (+0000) Subject: Fix problems in estimating the number of rows visited by a range query using sqlite_s... X-Git-Tag: version-3.8.1~132^2~24 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=b3c02e210f6cab7124252de36f1e44a03137cd01;p=thirdparty%2Fsqlite.git Fix problems in estimating the number of rows visited by a range query using sqlite_stat4 data when the column subject to the range query is not the leftmost of the index. FossilOrigin-Name: 9228aaf54dd2700c4f460f94f9c2309407578983 --- diff --git a/manifest b/manifest index f1338e1786..1d393f93d1 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index d8543e7110..944774c90e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e50dc30523210ba12324d5d8379503610f13aa34 \ No newline at end of file +9228aaf54dd2700c4f460f94f9c2309407578983 \ No newline at end of file diff --git a/src/where.c b/src/where.c index a8559bce86..cde57a1687 100644 --- a/src/where.c +++ b/src/where.c @@ -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( iNewpRec = 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( nNewnRecValid = 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; }