From: drh Date: Tue, 27 Jun 2006 01:54:26 +0000 (+0000) Subject: Cache and reuse virtual table index information in the optimizer. X-Git-Tag: version-3.6.10~2867 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6d209d8b0dc776cd53fb0b6892c95474aeb5c0b5;p=thirdparty%2Fsqlite.git Cache and reuse virtual table index information in the optimizer. Improved diagnostics for virtual table index selection. (CVS 3300) FossilOrigin-Name: 28413cf2b3f0e6f294e1f3c59fcce135b65c294f --- diff --git a/manifest b/manifest index c711df3f35..e41efea03a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Export\sthe\ssqlite3_bind_value\sAPI\sto\sloadable\sextensions.\s(CVS\s3299) -D 2006-06-27T00:14:28 +C Cache\sand\sreuse\svirtual\stable\sindex\sinformation\sin\sthe\soptimizer.\nImproved\sdiagnostics\sfor\svirtual\stable\sindex\sselection.\s(CVS\s3300) +D 2006-06-27T01:54:26 F Makefile.in f839b470345d3cb4b0644068474623fe2464b5d3 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -74,7 +74,7 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c ad73192b30a338a58fe81183d4a5d5a1d4e51d36 F src/sqlite.h.in af0ec0cfb2f8211e42cabf2523d1c8783f35ccaf F src/sqlite3ext.h c611255287e9a11ce4f1fe6251c2a0b9d32a828b -F src/sqliteInt.h 4b1a3193b875a4d56f07be87eb97d5014617fe60 +F src/sqliteInt.h b82962553a49eea4cd5c35634c7c9e0c93700814 F src/table.c e707e822aad688034d391b93df63d6b2d302fdca F src/tclsqlite.c 32d9e0147077f2e2c127c5f214fb3fe03ef97d18 F src/test1.c 233d5c83d11f34aa1c02eb72011ba9a30b72e078 @@ -105,7 +105,7 @@ F src/vdbeaux.c bb0a7b800a7167f2e49702a2bfc971919c0b99d1 F src/vdbefifo.c 9efb94c8c3f4c979ebd0028219483f88e57584f5 F src/vdbemem.c 5f0afe3b92bb2c037f8d5d697f7c151fa50783a3 F src/vtab.c 4751954e26e9caa6ce3ea5ad9468bd34f07d1de7 -F src/where.c 8ba6fa490be2d39ff8208a387816d3c61172a400 +F src/where.c 676105f882af3e58fd4cf75fb51746f8e9f70bdc F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/all.test 5df90d015ca63fcef2a4b62c24f7316b66c4bfd4 @@ -374,7 +374,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513 -P 85a66a25e97471d3c459c8da6a96990b0537dc7d -R 9b9a63db25a03e8a04d894575fa9aff2 +P 1ca385bb39514cb73f506bfbbe38aabb6b70816c +R 68db026572948c11690ddd8e3fadf452 U drh -Z 9d9f1e3d8238d70af115b74e0c7f2e43 +Z b6129eea235de4e5615a497f90bd0807 diff --git a/manifest.uuid b/manifest.uuid index 8afbcb8214..6e627fb2a2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1ca385bb39514cb73f506bfbbe38aabb6b70816c \ No newline at end of file +28413cf2b3f0e6f294e1f3c59fcce135b65c294f \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f973254c84..468af0f7ce 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.514 2006/06/26 21:35:45 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.515 2006/06/27 01:54:26 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1119,6 +1119,19 @@ struct SrcList { ** structure contains a single instance of this structure. This structure ** is intended to be private the the where.c module and should not be ** access or modified by other modules. +** +** The pIdxInfo and pBestIdx fields are used to help pick the best +** index on a virtual table. The pIdxInfo pointer contains indexing +** information for the i-th table in the FROM clause before reordering. +** All the pIdxInfo pointers are freed by whereInfoFree() in where.c. +** The pBestIdx pointer is a copy of pIdxInfo for the i-th table after +** FROM clause ordering. This is a little confusing so I will repeat +** it in different words. WhereInfo.a[i].pIdxInfo is index information +** for WhereInfo.pTabList.a[i]. WhereInfo.a[i].pBestInfo is the +** index information for the i-th loop of the join. pBestInfo is always +** either NULL or a copy of some pIdxInfo. So for cleanup it is +** sufficient to free all of the pIdxInfo pointers. +** */ struct WhereLevel { int iFrom; /* Which entry in the FROM clause */ @@ -1135,7 +1148,13 @@ struct WhereLevel { int nEq; /* Number of == or IN constraints on this loop */ int nIn; /* Number of IN operators constraining this loop */ int *aInLoop; /* Loop terminators for IN operators */ - sqlite3_index_info *pIdxInfo; /* Index information for virtual tables */ + sqlite3_index_info *pBestIdx; /* Index information for this level */ + + /* The following field is really not part of the current level. But + ** we need a place to cache index information for each table in the + ** FROM clause and the WhereLevel structure is a convenient place. + */ + sqlite3_index_info *pIdxInfo; /* Index info for n-th source table */ }; /* @@ -1152,6 +1171,7 @@ struct WhereInfo { int iContinue; /* Jump here to continue with next record */ int iBreak; /* Jump here to break out of the loop */ int nLevel; /* Number of nested loop */ + sqlite3_index_info **apInfo; /* Array of pointers to index info structures */ WhereLevel a[1]; /* Information about each nest loop in the WHERE */ }; diff --git a/src/where.c b/src/where.c index 963f0db29f..02b751e82d 100644 --- a/src/where.c +++ b/src/where.c @@ -16,7 +16,7 @@ ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** -** $Id: where.c,v 1.223 2006/06/24 11:51:35 danielk1977 Exp $ +** $Id: where.c,v 1.224 2006/06/27 01:54:26 drh Exp $ */ #include "sqliteInt.h" @@ -949,6 +949,51 @@ static double estLog(double N){ return logN; } +/* +** Two routines for printing the content of an sqlite3_index_info +** structure. Used for testing and debugging only. If neither +** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines +** are no-ops. +*/ +#if !defined(SQLITE_OMIT_VIRTUALTABLE) && \ + (defined(SQLITE_TEST) || defined(SQLITE_DEBUG)) +static void TRACE_IDX_INPUTS(sqlite3_index_info *p){ + int i; + if( !sqlite3_where_trace ) return; + for(i=0; inConstraint; i++){ + sqlite3DebugPrintf(" constraint[%d]: col=%d termid=%d op=%d usabled=%d\n", + i, + p->aConstraint[i].iColumn, + p->aConstraint[i].iTermOffset, + p->aConstraint[i].op, + p->aConstraint[i].usable); + } + for(i=0; inOrderBy; i++){ + sqlite3DebugPrintf(" orderby[%d]: col=%d desc=%d\n", + i, + p->aOrderBy[i].iColumn, + p->aOrderBy[i].desc); + } +} +static void TRACE_IDX_OUTPUTS(sqlite3_index_info *p){ + int i; + if( !sqlite3_where_trace ) return; + for(i=0; inConstraint; i++){ + sqlite3DebugPrintf(" usage[%d]: argvIdx=%d omit=%d\n", + i, + p->aConstraintUsage[i].argvIndex, + p->aConstraintUsage[i].omit); + } + sqlite3DebugPrintf(" idxNum=%d\n", p->idxNum); + sqlite3DebugPrintf(" idxStr=%s\n", p->idxStr); + sqlite3DebugPrintf(" orderByConsumed=%d\n", p->orderByConsumed); + sqlite3DebugPrintf(" estimatedCost=%g\n", p->estimatedCost); +} +#else +#define TRACE_IDX_INPUTS(A) +#define TRACE_IDX_OUTPUTS(A) +#endif + #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Compute the best index for a virtual table. @@ -993,6 +1038,7 @@ static double bestVirtualIndex( if( pIdxInfo==0 ){ WhereTerm *pTerm; int nTerm; + TRACE(("Recomputing index info for %s...\n", pTab->zName)); /* Count the number of possible WHERE clause constraints referring ** to this virtual table */ @@ -1125,7 +1171,10 @@ static double bestVirtualIndex( } sqlite3SafetyOff(pParse->db); + TRACE(("xBestIndex for %s\n", pTab->zName)); + TRACE_IDX_INPUTS(pIdxInfo); rc = pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo); + TRACE_IDX_OUTPUTS(pIdxInfo); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ){ sqlite3FailedMalloc(); @@ -1136,7 +1185,6 @@ static double bestVirtualIndex( }else{ rc = sqlite3SafetyOn(pParse->db); } - *(int*)&pIdxInfo->nOrderBy = nOrderBy; return pIdxInfo->estimatedCost; } @@ -1792,8 +1840,7 @@ WhereInfo *sqlite3WhereBegin( int bestJ = 0; /* The value of j */ Bitmask m; /* Bitmask value for j or bestJ */ int once = 0; /* True when first table is seen */ - sqlite3_index_info *pBestIndex = 0; - sqlite3_index_info *pIndex = 0; + sqlite3_index_info *pIndex; /* Current virtual index */ lowestCost = SQLITE_BIG_DBL; for(j=iFrom, pTabItem=&pTabList->a[j]; jnSrc; j++, pTabItem++){ @@ -1809,11 +1856,14 @@ WhereInfo *sqlite3WhereBegin( } assert( pTabItem->pTab ); #ifndef SQLITE_OMIT_VIRTUALTABLE + pIndex = 0; if( IsVirtual(pTabItem->pTab) ){ + sqlite3_index_info **ppIdxInfo = &pWInfo->a[j].pIdxInfo; cost = bestVirtualIndex(pParse, &wc, pTabItem, notReady, ppOrderBy ? *ppOrderBy : 0, i==0, - &pIndex); + ppIdxInfo); flags = WHERE_VIRTUALTABLE; + pIndex = *ppIdxInfo; if( pIndex && pIndex->orderByConsumed ){ flags = WHERE_VIRTUALTABLE | WHERE_ORDERBY; } @@ -1834,12 +1884,7 @@ WhereInfo *sqlite3WhereBegin( bestNEq = nEq; bestJ = j; #ifndef SQLITE_OMIT_VIRTUALTABLE - sqliteFree(pBestIndex); - pBestIndex = pIndex; - pIndex = 0; - }else{ - sqliteFree(pIndex); - pIndex = 0; + pLevel->pBestIdx = pIndex; #endif } if( doNotReorder ) break; @@ -1855,7 +1900,6 @@ WhereInfo *sqlite3WhereBegin( pLevel->nEq = bestNEq; pLevel->aInLoop = 0; pLevel->nIn = 0; - pLevel->pIdxInfo = pBestIndex; if( pBest ){ pLevel->iIdxCur = pParse->nTab++; }else{ @@ -1898,10 +1942,10 @@ WhereInfo *sqlite3WhereBegin( zMsg = sqlite3MPrintf("%z USING PRIMARY KEY", zMsg); } #ifndef SQLITE_OMIT_VIRTUALTABLE - else if( pLevel->pIdxInfo ){ - sqlite3_index_info *pIdxInfo = pLevel->pIdxInfo; + else if( pLevel->pBestIdx ){ + sqlite3_index_info *pBestIdx = pLevel->pBestIdx; zMsg = sqlite3MPrintf("%z VIRTUAL TABLE INDEX %d:%s", zMsg, - pIdxInfo->idxNum, pIdxInfo->idxStr); + pBestIdx->idxNum, pBestIdx->idxStr); } #endif if( pLevel->flags & WHERE_ORDERBY ){ @@ -1915,7 +1959,7 @@ WhereInfo *sqlite3WhereBegin( iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); if( pTab->isEphem || pTab->pSelect ) continue; #ifndef SQLITE_OMIT_VIRTUALTABLE - if( pLevel->pIdxInfo ){ + if( pLevel->pBestIdx ){ int iCur = pTabItem->iCursor; sqlite3VdbeOp3(v, OP_VOpen, iCur, 0, (const char*)pTab->pVtab, P3_VTAB); }else @@ -1988,17 +2032,17 @@ WhereInfo *sqlite3WhereBegin( } #ifndef SQLITE_OMIT_VIRTUALTABLE - if( pLevel->pIdxInfo ){ + if( pLevel->pBestIdx ){ /* Case 0: The table is a virtual-table. Use the VFilter and VNext ** to access the data. */ int ii; - sqlite3_index_info *pIdxInfo = pLevel->pIdxInfo; - int nConstraint = pIdxInfo->nConstraint; + sqlite3_index_info *pBestIdx = pLevel->pBestIdx; + int nConstraint = pBestIdx->nConstraint; struct sqlite3_index_constraint_usage *aUsage = - pIdxInfo->aConstraintUsage; + pBestIdx->aConstraintUsage; const struct sqlite3_index_constraint *aConstraint = - pIdxInfo->aConstraint; + pBestIdx->aConstraint; for(ii=1; ii<=nConstraint; ii++){ int j; @@ -2012,12 +2056,12 @@ WhereInfo *sqlite3WhereBegin( if( j==nConstraint ) break; } sqlite3VdbeAddOp(v, OP_Integer, ii-1, 0); - sqlite3VdbeAddOp(v, OP_Integer, pIdxInfo->idxNum, 0); - sqlite3VdbeOp3(v, OP_VFilter, iCur, brk, pIdxInfo->idxStr, - pIdxInfo->needToFreeIdxStr ? P3_MPRINTF : P3_STATIC); - pIdxInfo->needToFreeIdxStr = 0; - for(ii=0; iinConstraint; ii++){ - if( pIdxInfo->aConstraintUsage[ii].omit ){ + sqlite3VdbeAddOp(v, OP_Integer, pBestIdx->idxNum, 0); + sqlite3VdbeOp3(v, OP_VFilter, iCur, brk, pBestIdx->idxStr, + pBestIdx->needToFreeIdxStr ? P3_MPRINTF : P3_STATIC); + pBestIdx->needToFreeIdxStr = 0; + for(ii=0; iinConstraint; ii++){ + if( pBestIdx->aConstraintUsage[ii].omit ){ disableTerm(pLevel, &wc.a[ii]); } }