Cache and reuse virtual table index information in the optimizer.
Improved diagnostics for virtual table index selection. (CVS 3300) FossilOrigin-Name: 28413cf2b3f0e6f294e1f3c59fcce135b65c294f
This commit is contained in:
parent
c1be632489
commit
6d209d8b0d
14
manifest
14
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
|
||||
|
@ -1 +1 @@
|
||||
1ca385bb39514cb73f506bfbbe38aabb6b70816c
|
||||
28413cf2b3f0e6f294e1f3c59fcce135b65c294f
|
@ -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 */
|
||||
};
|
||||
|
||||
|
98
src/where.c
98
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; i<p->nConstraint; 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; i<p->nOrderBy; 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; i<p->nConstraint; 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]; j<pTabList->nSrc; 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; ii<pIdxInfo->nConstraint; 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; ii<pBestIdx->nConstraint; ii++){
|
||||
if( pBestIdx->aConstraintUsage[ii].omit ){
|
||||
disableTerm(pLevel, &wc.a[ii]);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user