mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-21 09:00:59 +03:00
Begin inserting some experimental code for the next generation query planner.
FossilOrigin-Name: ccaf4c3f7e1ec45e058d594d9b5c26818a37722a
This commit is contained in:
273
src/where.c
273
src/where.c
@@ -39,6 +39,43 @@ typedef struct WhereMaskSet WhereMaskSet;
|
||||
typedef struct WhereOrInfo WhereOrInfo;
|
||||
typedef struct WhereAndInfo WhereAndInfo;
|
||||
typedef struct WhereCost WhereCost;
|
||||
typedef struct WhereLoop WhereLoop;
|
||||
typedef struct WherePath WherePath;
|
||||
typedef struct WhereTerm WhereTerm;
|
||||
|
||||
/*
|
||||
** Each instance of this object represents a way of evaluating one
|
||||
** term of a join. The WhereClause object holds a table of these
|
||||
** objects using (iTab,prereq,iOb,nOb) as the primary key. Note that the
|
||||
** same join term might have multiple associated WhereLoop objects.
|
||||
*/
|
||||
struct WhereLoop {
|
||||
Bitmask prereq; /* Bitmask of other loops that must run first */
|
||||
int iTab; /* Index of the table coded by this loop */
|
||||
u16 iOb, nOb; /* ORDER BY terms satisfied by this strategy */
|
||||
double rSetup; /* One-time setup cost (ex: create transient index) */
|
||||
double rRun; /* Cost of running each loop */
|
||||
double nOut; /* Estimated number of output rows */
|
||||
u32 wsFlags; /* WHERE_* flags describing the plan */
|
||||
u16 nEq; /* Number of equality constraints */
|
||||
u16 nTerm; /* Number of entries in aTerm[] */
|
||||
Index *pIndex; /* Index used */
|
||||
WhereTerm *aTerm; /* WhereTerms used */
|
||||
WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
|
||||
};
|
||||
|
||||
/*
|
||||
** Each instance of this object holds a sequence of WhereLoop objects
|
||||
** that implement some or all of the entire query plan.
|
||||
*/
|
||||
struct WherePath {
|
||||
Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */
|
||||
double nRow; /* Estimated number of rows generated by this path */
|
||||
double rCost; /* Total cost of this path */
|
||||
WhereLoop *aLoop[1]; /* Array of WhereLoop objects implementing this path */
|
||||
WherePath *pNextPath; /* Next path in order of increasing cost */
|
||||
WherePath *pPrevPath; /* Previous path in cost order */
|
||||
};
|
||||
|
||||
/*
|
||||
** The query generator uses an array of instances of this structure to
|
||||
@@ -91,7 +128,6 @@ typedef struct WhereCost WhereCost;
|
||||
** in prereqRight and prereqAll. The default is 64 bits, hence SQLite
|
||||
** is only able to process joins with 64 or fewer tables.
|
||||
*/
|
||||
typedef struct WhereTerm WhereTerm;
|
||||
struct WhereTerm {
|
||||
Expr *pExpr; /* Pointer to the subexpression that is this term */
|
||||
int iParent; /* Disable pWC->a[iParent] when this term disabled */
|
||||
@@ -1793,9 +1829,9 @@ static void bestOrClauseIndex(WhereBestIdx *p){
|
||||
sBOI.pDistinct = 0;
|
||||
sBOI.ppIdxInfo = 0;
|
||||
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
|
||||
WHERETRACE(("... Multi-index OR testing for term %d of %d....\n",
|
||||
/*WHERETRACE(("... Multi-index OR testing for term %d of %d....\n",
|
||||
(pOrTerm - pOrWC->a), (pTerm - pWC->a)
|
||||
));
|
||||
));*/
|
||||
if( (pOrTerm->eOperator& WO_AND)!=0 ){
|
||||
sBOI.pWC = &pOrTerm->u.pAndInfo->wc;
|
||||
bestIndex(&sBOI);
|
||||
@@ -1822,15 +1858,15 @@ static void bestOrClauseIndex(WhereBestIdx *p){
|
||||
/* If there is an ORDER BY clause, increase the scan cost to account
|
||||
** for the cost of the sort. */
|
||||
if( p->pOrderBy!=0 ){
|
||||
WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n",
|
||||
rTotal, rTotal+nRow*estLog(nRow)));
|
||||
/*WHERETRACE(("... sorting increases OR cost %.9g to %.9g\n",
|
||||
rTotal, rTotal+nRow*estLog(nRow)));*/
|
||||
rTotal += nRow*estLog(nRow);
|
||||
}
|
||||
|
||||
/* If the cost of scanning using this OR term for optimization is
|
||||
** less than the current cost stored in pCost, replace the contents
|
||||
** of pCost. */
|
||||
WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow));
|
||||
/*WHERETRACE(("... multi-index OR cost=%.9g nrow=%.9g\n", rTotal, nRow));*/
|
||||
if( rTotal<p->cost.rCost ){
|
||||
p->cost.rCost = rTotal;
|
||||
p->cost.used = used;
|
||||
@@ -1927,8 +1963,8 @@ static void bestAutomaticIndex(WhereBestIdx *p){
|
||||
pWCEnd = &pWC->a[pWC->nTerm];
|
||||
for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){
|
||||
if( termCanDriveIndex(pTerm, pSrc, p->notReady) ){
|
||||
WHERETRACE(("auto-index reduces cost from %.1f to %.1f\n",
|
||||
p->cost.rCost, costTempIdx));
|
||||
/*WHERETRACE(("auto-index reduces cost from %.1f to %.1f\n",
|
||||
p->cost.rCost, costTempIdx));*/
|
||||
p->cost.rCost = costTempIdx;
|
||||
p->cost.plan.nRow = logN + 1;
|
||||
p->cost.plan.wsFlags = WHERE_TEMP_INDEX;
|
||||
@@ -2113,7 +2149,7 @@ static sqlite3_index_info *allocateIndexInfo(WhereBestIdx *p){
|
||||
int nOrderBy;
|
||||
sqlite3_index_info *pIdxInfo;
|
||||
|
||||
WHERETRACE(("Recomputing index info for %s...\n", pSrc->pTab->zName));
|
||||
/*WHERETRACE(("Recomputing index info for %s...\n", pSrc->pTab->zName));*/
|
||||
|
||||
/* Count the number of possible WHERE clause constraints referring
|
||||
** to this virtual table */
|
||||
@@ -2222,7 +2258,7 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
WHERETRACE(("xBestIndex for %s\n", pTab->zName));
|
||||
/*WHERETRACE(("xBestIndex for %s\n", pTab->zName));*/
|
||||
TRACE_IDX_INPUTS(p);
|
||||
rc = pVtab->pModule->xBestIndex(pVtab, p);
|
||||
TRACE_IDX_OUTPUTS(p);
|
||||
@@ -2733,8 +2769,8 @@ static int whereRangeScanEst(
|
||||
}else{
|
||||
*pRangeDiv = (double)p->aiRowEst[0]/(double)(iUpper - iLower);
|
||||
}
|
||||
WHERETRACE(("range scan regions: %u..%u div=%g\n",
|
||||
(u32)iLower, (u32)iUpper, *pRangeDiv));
|
||||
/*WHERETRACE(("range scan regions: %u..%u div=%g\n",
|
||||
(u32)iLower, (u32)iUpper, *pRangeDiv));*/
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
@@ -2791,7 +2827,7 @@ static int whereEqualScanEst(
|
||||
if( pRhs==0 ) return SQLITE_NOTFOUND;
|
||||
rc = whereKeyStats(pParse, p, pRhs, 0, a);
|
||||
if( rc==SQLITE_OK ){
|
||||
WHERETRACE(("equality scan regions: %d\n", (int)a[1]));
|
||||
/*WHERETRACE(("equality scan regions: %d\n", (int)a[1]));*/
|
||||
*pnRow = a[1];
|
||||
}
|
||||
whereEqualScanEst_cancel:
|
||||
@@ -2837,7 +2873,7 @@ static int whereInScanEst(
|
||||
if( rc==SQLITE_OK ){
|
||||
if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0];
|
||||
*pnRow = nRowEst;
|
||||
WHERETRACE(("IN row estimate: est=%g\n", nRowEst));
|
||||
/*WHERETRACE(("IN row estimate: est=%g\n", nRowEst));*/
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -3049,10 +3085,10 @@ static int isSortingIndex(
|
||||
}else{
|
||||
Expr *pRight = pConstraint->pExpr->pRight;
|
||||
if( pRight->op==TK_COLUMN ){
|
||||
WHERETRACE((" .. isOrderedColumn(tab=%d,col=%d)",
|
||||
pRight->iTable, pRight->iColumn));
|
||||
/*WHERETRACE((" .. isOrderedColumn(tab=%d,col=%d)",
|
||||
pRight->iTable, pRight->iColumn));*/
|
||||
isEq = isOrderedColumn(p, pRight->iTable, pRight->iColumn);
|
||||
WHERETRACE((" -> isEq=%d\n", isEq));
|
||||
/*WHERETRACE((" -> isEq=%d\n", isEq));*/
|
||||
|
||||
/* If the constraint is of the form X=Y where Y is an ordered value
|
||||
** in an outer loop, then make sure the sort order of Y matches the
|
||||
@@ -3319,10 +3355,10 @@ static void bestBtreeIndex(WhereBestIdx *p){
|
||||
WhereTerm *pFirstTerm = 0; /* First term matching the index */
|
||||
#endif
|
||||
|
||||
WHERETRACE((
|
||||
/*WHERETRACE((
|
||||
" %s(%s):\n",
|
||||
pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk")
|
||||
));
|
||||
));*/
|
||||
memset(&pc, 0, sizeof(pc));
|
||||
pc.plan.nOBSat = nPriorSat;
|
||||
|
||||
@@ -3403,10 +3439,10 @@ static void bestBtreeIndex(WhereBestIdx *p){
|
||||
if( bSort && (pSrc->jointype & JT_LEFT)==0 ){
|
||||
int bRev = 2;
|
||||
int bObUnique = 0;
|
||||
WHERETRACE((" --> before isSortIndex: nPriorSat=%d\n",nPriorSat));
|
||||
/*WHERETRACE((" --> before isSortIndex: nPriorSat=%d\n",nPriorSat));*/
|
||||
pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev, &bObUnique);
|
||||
WHERETRACE((" --> after isSortIndex: bRev=%d bObU=%d nOBSat=%d\n",
|
||||
bRev, bObUnique, pc.plan.nOBSat));
|
||||
/*WHERETRACE((" --> after isSortIndex: bRev=%d bObU=%d nOBSat=%d\n",
|
||||
bRev, bObUnique, pc.plan.nOBSat));*/
|
||||
if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
|
||||
pc.plan.wsFlags |= WHERE_ORDERED;
|
||||
if( bObUnique ) pc.plan.wsFlags |= WHERE_OB_UNIQUE;
|
||||
@@ -3634,14 +3670,14 @@ static void bestBtreeIndex(WhereBestIdx *p){
|
||||
}
|
||||
|
||||
|
||||
WHERETRACE((
|
||||
/*WHERETRACE((
|
||||
" nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n"
|
||||
" notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n"
|
||||
" used=0x%llx nOBSat=%d\n",
|
||||
pc.plan.nEq, nInMul, (int)rangeDiv, bSort, bLookup, pc.plan.wsFlags,
|
||||
p->notReady, log10N, pc.plan.nRow, pc.rCost, pc.used,
|
||||
pc.plan.nOBSat
|
||||
));
|
||||
));*/
|
||||
|
||||
/* If this index is the best we have seen so far, then record this
|
||||
** index and its cost in the p->cost structure.
|
||||
@@ -3677,9 +3713,9 @@ static void bestBtreeIndex(WhereBestIdx *p){
|
||||
|| p->cost.plan.u.pIdx==pSrc->pIndex
|
||||
);
|
||||
|
||||
WHERETRACE((" best index is %s cost=%.1f\n",
|
||||
/*WHERETRACE((" best index is %s cost=%.1f\n",
|
||||
p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk",
|
||||
p->cost.rCost));
|
||||
p->cost.rCost));*/
|
||||
|
||||
bestOrClauseIndex(p);
|
||||
bestAutomaticIndex(p);
|
||||
@@ -4928,6 +4964,13 @@ static int nQPlan = 0; /* Next free slow in _query_plan[] */
|
||||
|
||||
#endif /* SQLITE_TEST */
|
||||
|
||||
/*
|
||||
** Delete a WhereLoop object
|
||||
*/
|
||||
static void whereLoopDelete(sqlite3 *db, WhereLoop *p){
|
||||
sqlite3DbFree(db, p->aTerm);
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Free a WhereInfo structure
|
||||
@@ -4953,10 +4996,140 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
}
|
||||
}
|
||||
whereClauseClear(pWInfo->pWC);
|
||||
while( pWInfo->pLoops ){
|
||||
WhereLoop *p = pWInfo->pLoops;
|
||||
pWInfo->pLoops = p->pNextLoop;
|
||||
whereLoopDelete(db, p);
|
||||
}
|
||||
sqlite3DbFree(db, pWInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Insert or replace a WhereLoop entry using the template supplied.
|
||||
**
|
||||
** An existing WhereLoop entry might be overwritten if the new template
|
||||
** is better and has fewer dependencies. Or the template will be ignored
|
||||
** and no insert will occur if an existing WhereLoop is faster and has
|
||||
** fewer dependencies than the template. Otherwise a new WhereLoop is
|
||||
** added based no the template.
|
||||
*/
|
||||
static int whereLoopInsert(WhereInfo *pWInfo, WhereLoop *pTemplate){
|
||||
WhereLoop **ppPrev, *p;
|
||||
sqlite3 *db = pWInfo->pParse->db;
|
||||
|
||||
/* Search for an existing WhereLoop to overwrite, or which takes
|
||||
** priority over pTemplate.
|
||||
*/
|
||||
for(ppPrev=&pWInfo->pLoops, p=*ppPrev; p; ppPrev=&p->pNextLoop, p=*ppPrev){
|
||||
if( p->iTab!=pTemplate->iTab ) continue;
|
||||
if( (p->prereq & pTemplate->prereq)==p->prereq
|
||||
&& p->nOb>=pTemplate->nOb
|
||||
&& p->iOb==pTemplate->iOb
|
||||
&& p->rSetup<=pTemplate->rSetup
|
||||
&& p->rRun<=pTemplate->rRun
|
||||
){
|
||||
/* Already holding an equal or better WhereLoop.
|
||||
** Return without changing or adding anything */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq
|
||||
&& p->nOb<=pTemplate->nOb
|
||||
&& p->iOb==pTemplate->iOb
|
||||
&& p->rSetup>=pTemplate->rSetup
|
||||
&& p->rRun>=pTemplate->rRun
|
||||
){
|
||||
/* Overwrite an existing WhereLoop with a better one */
|
||||
sqlite3DbFree(db, p->aTerm);
|
||||
*ppPrev = p->pNextLoop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we reach this point it means that either p[] should be overwritten
|
||||
** with pTemplate[] if p[] exists, or if p==NULL then allocate a new
|
||||
** WhereLoop and insert it.
|
||||
*/
|
||||
if( p==0 ){
|
||||
p = sqlite3DbMallocRaw(db, sizeof(WhereLoop));
|
||||
if( p==0 ) return SQLITE_NOMEM;
|
||||
}
|
||||
*p = *pTemplate;
|
||||
p->pNextLoop = pWInfo->pLoops;
|
||||
pWInfo->pLoops = p;
|
||||
if( pTemplate->nTerm<=0 ) return SQLITE_OK;
|
||||
p->aTerm = sqlite3DbMallocRaw(db, pTemplate->nTerm*sizeof(p->aTerm[0]));
|
||||
if( p->aTerm==0 ){
|
||||
p->nTerm = 0;
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
memcpy(p->aTerm, pTemplate->aTerm, pTemplate->nTerm*sizeof(p->aTerm[0]));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add all WhereLoop objects for the iTab-th table of the join. That
|
||||
** table is guaranteed to be a b-tree table, not a virtual table.
|
||||
*/
|
||||
static void whereLoopAddBtree(
|
||||
WhereInfo *pWInfo, /* WHERE clause information */
|
||||
int iTab, /* The table to process */
|
||||
Bitmask mExtra /* Extra prerequesites for using this table */
|
||||
){
|
||||
WhereLoop *pNew; /* Template WhereLoop object */
|
||||
sqlite3 *db = pWInfo->pParse->db;
|
||||
|
||||
pNew = sqlite3DbMallocZero(db, sizeof(*pNew));
|
||||
if( pNew==0 ) return;
|
||||
|
||||
/* Insert a full table scan */
|
||||
pNew->iTab = iTab;
|
||||
pNew->rSetup = (double)0;
|
||||
pNew->rRun = (double)1000000;
|
||||
pNew->nOut = (double)1000000;
|
||||
whereLoopInsert(pWInfo, pNew);
|
||||
|
||||
whereLoopDelete(db, pNew);
|
||||
}
|
||||
|
||||
/*
|
||||
** Add all WhereLoop objects for the iTab-th table of the join. That
|
||||
** table is guaranteed to be a virtual table.
|
||||
*/
|
||||
static void whereLoopAddVirtual(
|
||||
WhereInfo *pWInfo, /* WHERE clause information */
|
||||
int iTab, /* The table to process */
|
||||
Bitmask mExtra /* Extra prerequesites for using this table */
|
||||
){
|
||||
}
|
||||
|
||||
/*
|
||||
** Add all WhereLoop objects for all tables
|
||||
*/
|
||||
static void whereLoopAddAll(WhereInfo *pWInfo){
|
||||
Bitmask mExtra = 0;
|
||||
Bitmask mPrior = 0;
|
||||
int iTab;
|
||||
SrcList *pTabList = pWInfo->pTabList;
|
||||
struct SrcList_item *pItem;
|
||||
WhereClause *pWC = pWInfo->pWC;
|
||||
sqlite3 *db = pWInfo->pParse->db;
|
||||
|
||||
/* Loop over the tables in the join, from left to right */
|
||||
for(iTab=0, pItem=pTabList->a; iTab<pTabList->nSrc; iTab++, pItem++){
|
||||
if( IsVirtual(pItem->pTab) ){
|
||||
whereLoopAddVirtual(pWInfo, iTab, mExtra);
|
||||
}else{
|
||||
whereLoopAddBtree(pWInfo, iTab, mExtra);
|
||||
}
|
||||
mPrior |= getMask(pWC->pMaskSet, pItem->iCursor);
|
||||
if( (pItem->jointype & (JT_LEFT|JT_CROSS))!=0 ){
|
||||
mExtra = mPrior;
|
||||
}
|
||||
if( db->mallocFailed ) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Generate the beginning of the loop used for WHERE clause processing.
|
||||
@@ -5187,6 +5360,35 @@ WhereInfo *sqlite3WhereBegin(
|
||||
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
|
||||
}
|
||||
|
||||
/* Construct the WhereLoop objects */
|
||||
WHERETRACE(("*** Optimizer Start ***\n"));
|
||||
whereLoopAddAll(pWInfo);
|
||||
|
||||
/* Display all of the WhereLoop objects if wheretrace is enabled */
|
||||
#if defined(SQLITE_DEBUG) \
|
||||
&& (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE))
|
||||
if( sqlite3WhereTrace ){
|
||||
WhereLoop *p;
|
||||
int nb = 2*((nTabList+15)/16);
|
||||
for(p=pWInfo->pLoops; p; p=p->pNextLoop){
|
||||
struct SrcList_item *pItem = pTabList->a + p->iTab;
|
||||
Table *pTab = pItem->pTab;
|
||||
sqlite3DebugPrintf("%02d.%0*llx", p->iTab, nb, p->prereq);
|
||||
sqlite3DebugPrintf(" %s",
|
||||
pItem->zAlias ? pItem->zAlias : pTab->zName);
|
||||
if( p->pIndex ){
|
||||
sqlite3DebugPrintf(" index %s nEq %d", p->pIndex->zName, p->nEq);
|
||||
}else{
|
||||
sqlite3DebugPrintf("\n");
|
||||
}
|
||||
sqlite3DebugPrintf(" wsFlags %08x OB %d,%d nTerm %d\n",
|
||||
p->wsFlags, p->iOb, p->nOb, p->nTerm);
|
||||
sqlite3DebugPrintf(" cost %.2e + %.2e nOut %.2e\n",
|
||||
p->prereq, p->rSetup, p->rRun, p->nOut);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Chose the best index to use for each table in the FROM clause.
|
||||
**
|
||||
** This loop fills in the following fields:
|
||||
@@ -5207,7 +5409,6 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sWBI.n = nTabList;
|
||||
sWBI.pDistinct = pDistinct;
|
||||
andFlags = ~0;
|
||||
WHERETRACE(("*** Optimizer Start ***\n"));
|
||||
for(sWBI.i=iFrom=0, pLevel=pWInfo->a; sWBI.i<nTabList; sWBI.i++, pLevel++){
|
||||
WhereCost bestPlan; /* Most efficient plan seen so far */
|
||||
Index *pIdx; /* Index for FROM table at pTabItem */
|
||||
@@ -5221,7 +5422,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
|
||||
memset(&bestPlan, 0, sizeof(bestPlan));
|
||||
bestPlan.rCost = SQLITE_BIG_DBL;
|
||||
WHERETRACE(("*** Begin search for loop %d ***\n", sWBI.i));
|
||||
/*WHERETRACE(("*** Begin search for loop %d ***\n", sWBI.i));*/
|
||||
|
||||
/* Loop through the remaining entries in the FROM clause to find the
|
||||
** next nested loop. The loop tests all FROM clause entries
|
||||
@@ -5304,8 +5505,8 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sWBI.notReady = (isOptimal ? m : sWBI.notValid);
|
||||
if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
|
||||
|
||||
WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n",
|
||||
j, sWBI.pSrc->pTab->zName, isOptimal));
|
||||
/*WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n",
|
||||
j, sWBI.pSrc->pTab->zName, isOptimal));*/
|
||||
assert( sWBI.pSrc->pTab );
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( IsVirtual(sWBI.pSrc->pTab) ){
|
||||
@@ -5335,9 +5536,9 @@ WhereInfo *sqlite3WhereBegin(
|
||||
** for the outer loop that table which benefits the least from
|
||||
** being in the inner loop. The following code scales the
|
||||
** outer loop cost estimate to accomplish that. */
|
||||
WHERETRACE((" scaling cost from %.1f to %.1f\n",
|
||||
/*WHERETRACE((" scaling cost from %.1f to %.1f\n",
|
||||
sWBI.cost.rCost,
|
||||
sWBI.cost.rCost/pWInfo->a[j].rOptCost));
|
||||
sWBI.cost.rCost/pWInfo->a[j].rOptCost));*/
|
||||
sWBI.cost.rCost /= pWInfo->a[j].rOptCost;
|
||||
}
|
||||
|
||||
@@ -5367,11 +5568,11 @@ WhereInfo *sqlite3WhereBegin(
|
||||
|| NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
|
||||
&& (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */
|
||||
){
|
||||
WHERETRACE((" === table %d (%s) is best so far\n"
|
||||
/*WHERETRACE((" === table %d (%s) is best so far\n"
|
||||
" cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n",
|
||||
j, sWBI.pSrc->pTab->zName,
|
||||
sWBI.cost.rCost, sWBI.cost.plan.nRow,
|
||||
sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
|
||||
sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));*/
|
||||
bestPlan = sWBI.cost;
|
||||
bestJ = j;
|
||||
}
|
||||
@@ -5388,11 +5589,11 @@ WhereInfo *sqlite3WhereBegin(
|
||||
testcase( bestJ>iFrom && (pTabList->a[iFrom].jointype & JT_CROSS)!=0 );
|
||||
testcase( bestJ>iFrom && bestJ<nTabList-1
|
||||
&& (pTabList->a[bestJ+1].jointype & JT_LEFT)!=0 );
|
||||
WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n"
|
||||
/*WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n"
|
||||
" cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n",
|
||||
bestJ, pTabList->a[bestJ].pTab->zName,
|
||||
pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow,
|
||||
bestPlan.plan.nOBSat, bestPlan.plan.wsFlags));
|
||||
bestPlan.plan.nOBSat, bestPlan.plan.wsFlags));*/
|
||||
if( (bestPlan.plan.wsFlags & WHERE_DISTINCT)!=0 ){
|
||||
assert( pWInfo->eDistinct==0 );
|
||||
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
|
||||
|
||||
Reference in New Issue
Block a user