-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
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
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
**
** 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 */
}
aStat[0] = iLower + iGap;
}
- return SQLITE_OK;
}
#endif /* SQLITE_ENABLE_STAT4 */
&& 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( iNew<iUpper ) iUpper = iNew;
}
}
+
pBuilder->pRec = 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( nNew<nOut ){
nOut = nNew;
if( bOk==0 ) return SQLITE_NOTFOUND;
pBuilder->nRecValid = 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;
}