From: drh Date: Tue, 25 Sep 2012 20:43:35 +0000 (+0000) Subject: Augment the WhereBestIdx structure to pass down into the query planner X-Git-Tag: version-3.7.15~112^2~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9cd1c99fe1f786e32623c4614d9b0b0c086ff441;p=thirdparty%2Fsqlite.git Augment the WhereBestIdx structure to pass down into the query planner information that might be used to better detect ORDER BY and DISTINCT optimizations spanning multiple tables of a join. FossilOrigin-Name: 4226e51ff837f0ffe16355491a655d919d13488e --- diff --git a/manifest b/manifest index 9b64595abd..28323b288a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Pass\sinformation\saround\sbetween\sthe\smajor\sroutines\sof\sthe\squery\splanner\nusing\sa\ssingle\spointer\sto\sa\sstructure\srather\sthan\sa\slong\slist\sof\sparameters. -D 2012-09-25T14:29:39.134 +C Augment\sthe\sWhereBestIdx\sstructure\sto\spass\sdown\sinto\sthe\squery\splanner\s\ninformation\sthat\smight\sbe\sused\sto\sbetter\sdetect\sORDER\sBY\sand\sDISTINCT\noptimizations\sspanning\smultiple\stables\sof\sa\sjoin. +D 2012-09-25T20:43:35.989 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5f4f26109f9d80829122e0e09f9cda008fa065fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -249,7 +249,7 @@ F src/vtab.c d8020c0a0e8ccc490ca449d7e665311b6e9f3ba9 F src/wal.c 5acb3e7bbd31f10ba39acad9ce6b399055337a9d F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b -F src/where.c 82be1d2f8f27012de0ed9d0977753ed24312b791 +F src/where.c e75e67f0631182be4ff0d325c5a1e4c4ec3d0962 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 0be144b453e0622a085fae8665c32f5676708e00 @@ -1016,10 +1016,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9 -P 349a55cd8ba9ce65ebfd987ecfebd1204f7d0a85 -R b0986bef8aa73322a60d8a15dd219873 -T *branch * qp-enhancements -T *sym-qp-enhancements * -T -sym-trunk * +P 1104d42e104d561ce60d05d158acfe499ee9fd50 +R 660ef52f8cc671ae827c548793cfd963 U drh -Z 6cfa0793222da70bc8fbd646a62c8a2a +Z 10b5de991bc34ec524f2e3adc126c5c7 diff --git a/manifest.uuid b/manifest.uuid index 4dfae10d21..1edaad7ba3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1104d42e104d561ce60d05d158acfe499ee9fd50 \ No newline at end of file +4226e51ff837f0ffe16355491a655d919d13488e \ No newline at end of file diff --git a/src/where.c b/src/where.c index 66fe0516a6..63823f277d 100644 --- a/src/where.c +++ b/src/where.c @@ -284,6 +284,8 @@ struct WhereBestIdx { ExprList *pOrderBy; /* The ORDER BY clause */ ExprList *pDistinct; /* The select-list if query is DISTINCT */ sqlite3_index_info **ppIdxInfo; /* Index information passed to xBestIndex */ + int i, n; /* Which loop is being coded; # of loops */ + WhereLevel *a; /* Info about outer loops */ WhereCost cost; /* Lowest cost query plan */ }; @@ -3037,14 +3039,22 @@ static void bestBtreeIndex(WhereBestIdx *p){ int nInMul = 1; /* Number of distinct equalities to lookup */ double rangeDiv = (double)1; /* Estimated reduction in search space */ int nBound = 0; /* Number of range constraints seen */ - int bSort = !!p->pOrderBy; /* True if external sort required */ - int bDist = !!p->pDistinct; /* True if index cannot help with DISTINCT */ + int bSort; /* True if external sort required */ + int bDist; /* True if index cannot help with DISTINCT */ int bLookup = 0; /* True if not a covering index */ WhereTerm *pTerm; /* A single term of the WHERE clause */ #ifdef SQLITE_ENABLE_STAT3 WhereTerm *pFirstTerm = 0; /* First term matching the index */ #endif + if( (p->i) > 0 ){ + bSort = 0; + bDist = 0; + }else{ + bSort = p->pOrderBy!=0; + bDist = p->pDistinct!=0; + } + /* Determine the values of nEq and nInMul */ for(nEq=0; nEqnColumn; nEq++){ int j = pProbe->aiColumn[nEq]; @@ -3114,7 +3124,7 @@ static void bestBtreeIndex(WhereBestIdx *p){ ** naturally scan rows in the required order, set the appropriate flags ** in wsFlags. Otherwise, if there is an ORDER BY clause but the index ** will scan rows in a different order, set the bSort variable. */ - if( isSortingIndex( + if( bSort && isSortingIndex( pParse, pWC->pMaskSet, pProbe, iCur, p->pOrderBy, nEq, wsFlags, &rev) ){ bSort = 0; @@ -3125,7 +3135,8 @@ static void bestBtreeIndex(WhereBestIdx *p){ /* If there is a DISTINCT qualifier and this index will scan rows in ** order of the DISTINCT expressions, clear bDist and set the appropriate ** flags in wsFlags. */ - if( isDistinctIndex(pParse, pWC, pProbe, iCur, p->pDistinct, nEq) + if( bDist + && isDistinctIndex(pParse, pWC, pProbe, iCur, p->pDistinct, nEq) && (wsFlags & WHERE_COLUMN_IN)==0 ){ bDist = 0; @@ -4690,7 +4701,6 @@ WhereInfo *sqlite3WhereBegin( u16 wctrlFlags, /* One of the WHERE_* flags defined in sqliteInt.h */ int iIdxCur /* If WHERE_ONETABLE_ONLY is set, index cursor number */ ){ - int i; /* Loop counter */ int nByteWInfo; /* Num. bytes allocated for WhereInfo struct */ int nTabList; /* Number of elements in pTabList */ WhereInfo *pWInfo; /* Will become the return value of this function */ @@ -4701,6 +4711,7 @@ WhereInfo *sqlite3WhereBegin( WhereLevel *pLevel; /* A single level in pWInfo->a[] */ int iFrom; /* First unused FROM clause element */ int andFlags; /* AND-ed combination of all pWC->a[].wtFlags */ + int ii; /* Loop counter */ sqlite3 *db; /* Database connection */ @@ -4751,6 +4762,7 @@ WhereInfo *sqlite3WhereBegin( pWInfo->wctrlFlags = wctrlFlags; pWInfo->savedNQueryLoop = pParse->nQueryLoop; pMaskSet = (WhereMaskSet*)&sWBI.pWC[1]; + sWBI.a = pWInfo->a; /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ @@ -4794,19 +4806,19 @@ WhereInfo *sqlite3WhereBegin( ** WHERE_ONETABLE_ONLY flag is set. */ assert( sWBI.pWC->vmask==0 && pMaskSet->n==0 ); - for(i=0; inSrc; i++){ - createMask(pMaskSet, pTabList->a[i].iCursor); + for(ii=0; iinSrc; ii++){ + createMask(pMaskSet, pTabList->a[ii].iCursor); #ifndef SQLITE_OMIT_VIRTUALTABLE - if( ALWAYS(pTabList->a[i].pTab) && IsVirtual(pTabList->a[i].pTab) ){ - sWBI.pWC->vmask |= ((Bitmask)1 << i); + if( ALWAYS(pTabList->a[ii].pTab) && IsVirtual(pTabList->a[ii].pTab) ){ + sWBI.pWC->vmask |= ((Bitmask)1 << ii); } #endif } #ifndef NDEBUG { Bitmask toTheLeft = 0; - for(i=0; inSrc; i++){ - Bitmask m = getMask(pMaskSet, pTabList->a[i].iCursor); + for(ii=0; iinSrc; ii++){ + Bitmask m = getMask(pMaskSet, pTabList->a[ii].iCursor); assert( (m-1)==toTheLeft ); toTheLeft |= m; } @@ -4847,10 +4859,13 @@ WhereInfo *sqlite3WhereBegin( ** This loop also figures out the nesting order of tables in the FROM ** clause. */ - notReady = ~(Bitmask)0; + sWBI.notValid = ~(Bitmask)0; + sWBI.pOrderBy = pOrderBy; + sWBI.n = nTabList; + sWBI.pDistinct = pDistinct; andFlags = ~0; WHERETRACE(("*** Optimizer Start ***\n")); - for(i=iFrom=0, pLevel=pWInfo->a; ia; sWBI.ijointype & (JT_LEFT|JT_CROSS))!=0; if( j!=iFrom && doNotReorder ) break; m = getMask(pMaskSet, sWBI.pSrc->iCursor); - if( (m & notReady)==0 ){ + if( (m & sWBI.notValid)==0 ){ if( j==iFrom ) iFrom++; continue; } - sWBI.notValid = notReady; - sWBI.notReady = (isOptimal ? m : notReady); - sWBI.pOrderBy = (i==0) ? pOrderBy : 0; - sWBI.pDistinct = (i==0 ? pDistinct : 0); + sWBI.notReady = (isOptimal ? m : sWBI.notValid); if( sWBI.pSrc->pIndex==0 ) nUnconstrained++; WHERETRACE(("=== trying table %d with isOptimal=%d ===\n", @@ -4938,7 +4950,7 @@ WhereInfo *sqlite3WhereBegin( { bestBtreeIndex(&sWBI); } - assert( isOptimal || (sWBI.cost.used¬Ready)==0 ); + assert( isOptimal || (sWBI.cost.used&sWBI.notValid)==0 ); /* If an INDEXED BY clause is present, then the plan must use that ** index if it uses any index at all */ @@ -4953,7 +4965,8 @@ WhereInfo *sqlite3WhereBegin( /* Conditions under which this table becomes the best so far: ** ** (1) The table must not depend on other tables that have not - ** yet run. + ** yet run. (In other words, it must not depend on tables + ** in inner loops.) ** ** (2) A full-table-scan plan cannot supercede indexed plan unless ** the full-table-scan is an "optimal" plan as defined above. @@ -4970,7 +4983,7 @@ WhereInfo *sqlite3WhereBegin( ** (4) The plan cost must be lower than prior plans or else the ** cost must be the same and the number of rows must be lower. */ - if( (sWBI.cost.used¬Ready)==0 /* (1) */ + if( (sWBI.cost.used&sWBI.notValid)==0 /* (1) */ && (bestJ<0 || (notIndexed&m)!=0 /* (2) */ || (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0) @@ -4990,7 +5003,7 @@ WhereInfo *sqlite3WhereBegin( } } assert( bestJ>=0 ); - assert( notReady & getMask(pMaskSet, pTabList->a[bestJ].iCursor) ); + assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) ); WHERETRACE(("*** Optimizer selects table %d for loop %d" " with cost=%g and nRow=%g\n", bestJ, pLevel-pWInfo->a, bestPlan.rCost, bestPlan.plan.nRow)); @@ -5016,7 +5029,7 @@ WhereInfo *sqlite3WhereBegin( }else{ pLevel->iIdxCur = -1; } - notReady &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor); + sWBI.notValid &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor); pLevel->iFrom = (u8)bestJ; if( bestPlan.plan.nRow>=(double)1 ){ pParse->nQueryLoop *= bestPlan.plan.nRow; @@ -5069,7 +5082,7 @@ WhereInfo *sqlite3WhereBegin( sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ notReady = ~(Bitmask)0; pWInfo->nRowOut = (double)1; - for(i=0, pLevel=pWInfo->a; ia; iia[i]; - explainOneScan(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags); - notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady); + for(ii=0; iia[ii]; + explainOneScan(pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags); + notReady = codeOneLoopStart(pWInfo, ii, wctrlFlags, notReady); pWInfo->iContinue = pLevel->addrCont; } @@ -5146,13 +5159,13 @@ WhereInfo *sqlite3WhereBegin( ** the index is listed as "{}". If the primary key is used the ** index name is '*'. */ - for(i=0; ia[i]; + pLevel = &pWInfo->a[ii]; w = pLevel->plan.wsFlags; pTabItem = &pTabList->a[pLevel->iFrom]; z = pTabItem->zAlias;