1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-16 23:02:26 +03:00

First version of sqlite_stat2 (schema forces exactly 10 samples).

FossilOrigin-Name: dd96bda2a85c1d94fb4a0bf5f27e2977f7f7e42e
This commit is contained in:
dan
2009-08-17 17:06:58 +00:00
parent d9c50f7fed
commit 02fa469619
12 changed files with 469 additions and 99 deletions

View File

@@ -1890,6 +1890,177 @@ static void bestVirtualIndex(
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
/*
** Argument pIdx is a pointer to an index structure that has an array of
** SQLITE_INDEX_SAMPLES evenly spaced samples of the first indexed column
** stored in Index.aSample. The domain of values stored in said column
** may be thought of as divided into (SQLITE_INDEX_SAMPLES+1) regions.
** Region 0 contains all values smaller than the first sample value. Region
** 1 contains values larger than or equal to the value of the first sample,
** but smaller than the value of the second. And so on.
**
** If successful, this function determines which of the regions value
** pVal lies in, sets *piRegion to the region index and returns SQLITE_OK.
** Or, if an OOM occurs while converting text values between encodings,
** SQLITE_NOMEM is returned.
*/
static int whereRangeRegion(
Parse *pParse, /* Database connection */
Index *pIdx, /* Index to consider domain of */
sqlite3_value *pVal, /* Value to consider */
int *piRegion /* OUT: Region of domain in which value lies */
){
if( pVal ){
IndexSample *aSample = pIdx->aSample;
int i = 0;
int eType = sqlite3_value_type(pVal);
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
double r = sqlite3_value_double(pVal);
for(i=0; i<SQLITE_INDEX_SAMPLES; i++){
if( aSample[i].eType==SQLITE_NULL ) continue;
if( aSample[i].eType>=SQLITE_TEXT || aSample[i].u.r>r ) break;
}
}else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
sqlite3 *db = pParse->db;
CollSeq *pColl;
const u8 *z;
int n;
if( eType==SQLITE_BLOB ){
z = (const u8 *)sqlite3_value_blob(pVal);
pColl = db->pDfltColl;
assert( pColl->enc==SQLITE_UTF8 );
}else{
pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, *pIdx->azColl, 0);
if( sqlite3CheckCollSeq(pParse, pColl) ){
return SQLITE_ERROR;
}
z = (const u8 *)sqlite3ValueText(pVal, pColl->enc);
if( !z ){
return SQLITE_NOMEM;
}
assert( z && pColl && pColl->xCmp );
}
n = sqlite3ValueBytes(pVal, pColl->enc);
for(i=0; i<SQLITE_INDEX_SAMPLES; i++){
int r;
int eSampletype = aSample[i].eType;
if( eSampletype==SQLITE_NULL || eSampletype<eType ) continue;
if( (eSampletype!=eType) ) break;
if( pColl->enc==SQLITE_UTF8 ){
r = pColl->xCmp(pColl->pUser, aSample[i].nByte, aSample[i].u.z, n, z);
}else{
int nSample;
char *zSample = sqlite3Utf8to16(
db, pColl->enc, aSample[i].u.z, aSample[i].nByte, &nSample
);
if( !zSample ){
assert( db->mallocFailed );
return SQLITE_NOMEM;
}
r = pColl->xCmp(pColl->pUser, nSample, zSample, n, z);
sqlite3DbFree(db, zSample);
}
if( r>0 ) break;
}
}
*piRegion = i;
}
return SQLITE_OK;
}
/*
** This function is used to estimate the number of rows that will be visited
** by scanning an index for a range of values. The range may have an upper
** bound, a lower bound, or both. The WHERE clause terms that set the upper
** and lower bounds are represented by pLower and pUpper respectively. For
** example, assuming that index p is on t1(a):
**
** ... FROM t1 WHERE a > ? AND a < ? ...
** |_____| |_____|
** | |
** pLower pUpper
**
** If the upper or lower bound is not present, then NULL should be passed in
** place of a WhereTerm.
**
** The nEq parameter is passed the index of the index column subject to the
** range constraint. Or, equivalently, the number of equality constraints
** optimized by the proposed index scan. For example, assuming index p is
** on t1(a, b), and the SQL query is:
**
** ... FROM t1 WHERE a = ? AND b > ? AND b < ? ...
**
** then nEq should be passed the value 1 (as the range restricted column,
** b, is the second left-most column of the index). Or, if the query is:
**
** ... FROM t1 WHERE a > ? AND a < ? ...
**
** then nEq should be passed 0.
**
** The returned value is an integer between 1 and 9, inclusive. A return
** value of 1 indicates that the proposed range scan is expected to visit
** approximately 1/9 (11%) of the rows selected by the nEq equality constraints
** (if any). A return value of 9 indicates that it is expected that the
** range scan will visit 9/9 (100%) of the rows selected by the equality
** constraints.
*/
static int whereRangeScanEst(
Parse *pParse,
Index *p,
int nEq,
WhereTerm *pLower,
WhereTerm *pUpper,
int *piEst /* OUT: Return value */
){
sqlite3 *db = pParse->db;
sqlite3_value *pLowerVal = 0;
sqlite3_value *pUpperVal = 0;
int rc = SQLITE_OK;
if( nEq==0 && p->aSample ){
int iEst;
int iUpper = SQLITE_INDEX_SAMPLES;
int iLower = 0;
u8 aff = p->pTable->aCol[0].affinity;
if( pLower ){
Expr *pExpr = pLower->pExpr->pRight;
rc = sqlite3ValueFromExpr(db, pExpr, SQLITE_UTF8, aff, &pLowerVal);
if( !pLowerVal ) goto fallback;
}
if( pUpper ){
Expr *pExpr = pUpper->pExpr->pRight;
rc = sqlite3ValueFromExpr(db, pExpr, SQLITE_UTF8, aff, &pUpperVal);
if( !pUpperVal ){
sqlite3ValueFree(pLowerVal);
goto fallback;
}
}
rc = whereRangeRegion(pParse, p, pUpperVal, &iUpper);
if( rc==SQLITE_OK ){
rc = whereRangeRegion(pParse, p, pLowerVal, &iLower);
}
iEst = iUpper - iLower;
if( iEst>=SQLITE_INDEX_SAMPLES ) iEst = SQLITE_INDEX_SAMPLES-1;
else if( iEst<1 ) iEst = 1;
sqlite3ValueFree(pLowerVal);
sqlite3ValueFree(pUpperVal);
*piEst = iEst;
return rc;
}
fallback:
assert( pLower || pUpper );
*piEst = (SQLITE_INDEX_SAMPLES-1) / ((pLower&&pUpper)?9:3);
return rc;
}
/*
** Find the query plan for accessing a particular table. Write the
** best query plan and its cost into the WhereCost object supplied as the
@@ -2043,7 +2214,7 @@ static void bestBtreeIndex(
int nEq;
int bInEst = 0;
int nInMul = 1;
int nBound = 1;
int nBound = 9;
int bSort = 0;
int bLookup = 0;
@@ -2075,14 +2246,13 @@ static void bestBtreeIndex(
if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){
WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx);
WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx);
whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &nBound);
if( pTop ){
wsFlags |= WHERE_TOP_LIMIT;
nBound *= 3;
used |= pTop->prereqRight;
}
if( pBtm ){
wsFlags |= WHERE_BTM_LIMIT;
nBound *= 3;
used |= pBtm->prereqRight;
}
wsFlags |= (WHERE_COLUMN_RANGE|WHERE_ROWID_RANGE);
@@ -2152,8 +2322,8 @@ static void bestBtreeIndex(
nInMul = nRow / aiRowEst[nEq];
}
cost = nRow + nInMul*estLog(aiRowEst[0]);
nRow /= nBound;
cost /= nBound;
nRow = nRow * (double)nBound / 9.0;
cost = cost * (double)nBound / 9.0;
if( bSort ){
cost += cost*estLog(cost);
}