1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-21 09:00:59 +03:00

Update the NGQP so that it can produce plans that include automatic indices.

FossilOrigin-Name: 586b55d8d7722de1c0530b3b832bae0511e6d05c
This commit is contained in:
drh
2013-05-10 15:16:30 +00:00
parent b2a90f09b8
commit eb04de3224
3 changed files with 72 additions and 13 deletions

View File

@@ -289,6 +289,7 @@ struct WhereLoopBuilder {
SrcList *pTabList; /* FROM clause */
ExprList *pOrderBy; /* ORDER BY clause */
WhereLoop *pNew; /* Template WhereLoop */
int mxTerm; /* Maximum number of aTerm[] entries on pNew */
};
/*
@@ -5241,6 +5242,7 @@ static int whereLoopAddBtreeIndex(
WhereLoop savedLoop; /* Saved original content of pNew[] */
int iCol; /* Index of the column in the table */
int rc = SQLITE_OK; /* Return code */
double rLogSize; /* Logarithm of table size */
db = pBuilder->db;
pNew = pBuilder->pNew;
@@ -5262,10 +5264,12 @@ static int whereLoopAddBtreeIndex(
opMask, iCol>=0 ? pProbe : 0);
savedLoop = *pNew;
pNew->rSetup = (double)0;
rLogSize = estLog(pProbe->aiRowEst[0]);
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
int nIn = 1;
pNew->u.btree.nEq = savedLoop.u.btree.nEq;
pNew->nTerm = savedLoop.nTerm;
if( pNew->nTerm>=pBuilder->mxTerm ) break; /* Repeated column in index */
pNew->aTerm[pNew->nTerm++] = pTerm;
pNew->prereq = (savedLoop.prereq | pTerm->prereqRight) & ~pNew->maskSelf;
if( pTerm->eOperator & WO_IN ){
@@ -5291,7 +5295,16 @@ static int whereLoopAddBtreeIndex(
pNew->wsFlags |= WHERE_COLUMN_RANGE|WHERE_TOP_LIMIT;
pNew->nOut = savedLoop.nOut/3;
}
pNew->rRun = pNew->nOut + estLog(pProbe->aiRowEst[0])*nIn;
pNew->rRun = rLogSize*nIn; /* Cost for nIn binary searches */
if( pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK) ){
pNew->rRun += pNew->nOut; /* Unit step cost to reach each row */
}else{
/* Each row involves a step of the index, then a binary search of
** the main table */
pNew->rRun += pNew->nOut*(1 + rLogSize);
}
/* TBD: Adjust nOut and rRun for STAT3 range values */
/* TBD: Adjust nOut for additional constraints */
rc = whereLoopInsert(pBuilder->pWInfo, pNew);
if( (pNew->wsFlags & WHERE_TOP_LIMIT)==0
&& pNew->u.btree.nEq<pProbe->nColumn
@@ -5318,6 +5331,8 @@ static int whereLoopAddBtree(
struct SrcList_item *pSrc; /* The FROM clause btree term to add */
WhereLoop *pNew; /* Template WhereLoop object */
int rc = SQLITE_OK; /* Return code */
double rSize; /* number of rows in the table */
double rLogSize; /* Logarithm of the number of rows in the table */
pNew = pBuilder->pNew;
pSrc = pBuilder->pTabList->a + pNew->iTab;
@@ -5347,6 +5362,33 @@ static int whereLoopAddBtree(
}
pProbe = &sPk;
}
rSize = (double)pSrc->pTab->nRowEst;
rLogSize = estLog(rSize);
/* Automatic indexes */
if( (pBuilder->pParse->db->flags & SQLITE_AutoIndex)!=0
&& !pSrc->viaCoroutine
&& !pSrc->notIndexed
&& !pSrc->isCorrelated
){
/* Generate auto-index WhereLoops */
WhereClause *pWC = pBuilder->pWC;
WhereTerm *pTerm;
WhereTerm *pWCEnd = pWC->a + pWC->nTerm;
for(pTerm=pWC->a; rc==SQLITE_OK && pTerm<pWCEnd; pTerm++){
if( termCanDriveIndex(pTerm, pSrc, 0) ){
pNew->u.btree.nEq = 1;
pNew->nTerm = 1;
pNew->aTerm[0] = pTerm;
pNew->rSetup = 2*rLogSize*pSrc->pTab->nRowEst;
pNew->nOut = (double)10;
pNew->rRun = rLogSize + pNew->nOut;
pNew->wsFlags = WHERE_TEMP_INDEX;
pNew->prereq = mExtra | pTerm->prereqRight;
rc = whereLoopInsert(pBuilder->pWInfo, pNew);
}
}
}
/* Insert a full table scan */
pNew->u.btree.nEq = 0;
@@ -5355,12 +5397,11 @@ static int whereLoopAddBtree(
pNew->prereq = mExtra;
pNew->u.btree.pIndex = 0;
pNew->wsFlags = 0;
pNew->rRun = (double)pSrc->pTab->nRowEst;
pNew->nOut = (double)pSrc->pTab->nRowEst;
pNew->nOut = rSize;
pNew->rRun = rSize + rLogSize;
/* TBD: Reduce nOut using constraints */
rc = whereLoopInsert(pBuilder->pWInfo, pNew);
/* TBD: Insert automatic index opportunities */
/* Loop over all indices
*/
for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext){
@@ -5478,6 +5519,7 @@ static int whereLoopAddVirtual(
if( rc ) goto whereLoopAddVtab_exit;
pIdxCons = *(struct sqlite3_index_constraint**)&pIdxInfo->aConstraint;
pNew->prereq = 0;
assert( pIdxInfo->nConstraint<=pBuilder->mxTerm );
for(i=0; i<pIdxInfo->nConstraint; i++) pNew->aTerm[i] = 0;
mxTerm = -1;
for(i=0; i<pIdxInfo->nConstraint; i++, pIdxCons++){
@@ -5555,7 +5597,13 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){
/* Loop over the tables in the join, from left to right */
pBuilder->pNew = pNew = sqlite3DbMallocZero(db, sizeof(WhereLoop));
if( pNew==0 ) return SQLITE_NOMEM;
pNew->aTerm = sqlite3DbMallocZero(db, (pWC->nTerm+1)*sizeof(pNew->aTerm[0]));
pBuilder->mxTerm = pWC->nTerm+1;
while( pWC->pOuter ){
pWC = pWC->pOuter;
pBuilder->mxTerm += pWC->nTerm;
}
pWC = pBuilder->pWC;
pNew->aTerm = sqlite3DbMallocZero(db,pBuilder->mxTerm*sizeof(pNew->aTerm[0]));
if( pNew->aTerm==0 ){
rc = SQLITE_NOMEM;
goto whereLoopAddAll_end;
@@ -6331,6 +6379,17 @@ WhereInfo *sqlite3WhereBegin(
pWInfo->a[0].plan.wsFlags &= ~WHERE_IDX_ONLY;
}
#if 0
/* Scaffolding: Check the new query plan against the old. Report any
** discrepencies */
for(ii=0; ii<nTabList; ii++){
if( pWInfo->a[ii].iFrom!=pWInfo->a[ii].pWLoop->iTab ){
sqlite3DebugPrintf("(QP-Mismatch)");
break;
}
}
#endif
/* Open all tables in the pTabList and any indices selected for
** searching those tables.
*/