]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Cache and reuse virtual table index information in the optimizer.
authordrh <drh@noemail.net>
Tue, 27 Jun 2006 01:54:26 +0000 (01:54 +0000)
committerdrh <drh@noemail.net>
Tue, 27 Jun 2006 01:54:26 +0000 (01:54 +0000)
Improved diagnostics for virtual table index selection. (CVS 3300)

FossilOrigin-Name: 28413cf2b3f0e6f294e1f3c59fcce135b65c294f

manifest
manifest.uuid
src/sqliteInt.h
src/where.c

index c711df3f35739c7cf6ab9fa4a98936486c40222d..e41efea03aef71597cf44690793ece1e45137d59 100644 (file)
--- 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
index 8afbcb8214c14599920abc121b641c94ba2a50ca..6e627fb2a2fa469b58b7f76e4524607b9a80afaa 100644 (file)
@@ -1 +1 @@
-1ca385bb39514cb73f506bfbbe38aabb6b70816c
\ No newline at end of file
+28413cf2b3f0e6f294e1f3c59fcce135b65c294f
\ No newline at end of file
index f973254c84ba4d7c5c8ae38320c0a499fce732cf..468af0f7ced155ad76a52946de02178becf5269c 100644 (file)
@@ -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 */
 };
 
index 963f0db29f125a4de828e734e433ed1b5275e801..02b751e82db8d7e56dd2e63985138221134d7545 100644 (file)
@@ -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]);
         }
       }