]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Multi-index OR-clause optimization now works for simple tests. There are
authordrh <drh@noemail.net>
Tue, 23 Dec 2008 13:35:23 +0000 (13:35 +0000)
committerdrh <drh@noemail.net>
Tue, 23 Dec 2008 13:35:23 +0000 (13:35 +0000)
no test scripts for it yet, though.  And it is disabled by default, pending
further testing and optimization.  We need a lot of both. (CVS 6058)

FossilOrigin-Name: d77a702358deddfa9987147999d06a235e730fa9

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

index 5760c8ec05df416d6fa19ee3128017cdcd3aec4c..877f93b73a8b5ecb78b966bf2ced7aa87706ca27 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sa\stest\sto\ssavepoint.test\sthat\stests\sthat\snothing\sgoes\swrong\sif\san\sincremental\svacuum\soccurs\sinside\sa\ssavepoint.\s(CVS\s6057)
-D 2008-12-23T11:46:28
+C Multi-index\sOR-clause\soptimization\snow\sworks\sfor\ssimple\stests.\s\sThere\sare\nno\stest\sscripts\sfor\sit\syet,\sthough.\s\sAnd\sit\sis\sdisabled\sby\sdefault,\spending\nfurther\stesting\sand\soptimization.\s\sWe\sneed\sa\slot\sof\sboth.\s(CVS\s6058)
+D 2008-12-23T13:35:23
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 77635d0909c2067cee03889a1e04ce910d8fb809
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -158,7 +158,7 @@ F src/select.c a4316c5e8a417687e159b3d3ae689363d1dec5df
 F src/shell.c 65d19f8996a160f288087e31810f24025439c62a
 F src/sqlite.h.in 065a828e299960316aa34f05b9f0f10f33afe4c8
 F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
-F src/sqliteInt.h 24f71f7e2758516aa6b64e1f0ca02ee6e29344d3
+F src/sqliteInt.h 9411acda2959c3494bafb1ac98048a53ee920ea3
 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
 F src/table.c 23db1e5f27c03160987c122a078b4bb51ef0b2f8
@@ -198,7 +198,7 @@ F src/update.c 080889d241e4dcd1c545c8051eb6de86f4939295
 F src/utf.c 1da9c832dba0fa8f865b5b902d93f420a1ee4245
 F src/util.c ea62608f66f33a7e8322de83024ae37c415c0c7f
 F src/vacuum.c 383d6297bddc011ab04a9eed110db6eaf523e8e9
-F src/vdbe.c e9a7825d25496343937852fa70b993ee217f924e
+F src/vdbe.c fb84f5ce769c74348d808cdc6fbba91aec54fe30
 F src/vdbe.h 03516f28bf5aca00a53c4dccd6c313f96adb94f6
 F src/vdbeInt.h e6e80a99ce634983b7cc2498843b4d2e5540900a
 F src/vdbeapi.c 85c33cfbfa56249cbe627831610afafba754477d
@@ -207,7 +207,7 @@ F src/vdbeblob.c b0dcebfafedcf9c0addc7901ad98f6f986c08935
 F src/vdbemem.c f9c859ac17e2e05a0f249868ce4f191f69edd31d
 F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43
 F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d
-F src/where.c 6e5de2421da8d9ed62a2fcf7df70df8301282936
+F src/where.c 50e47032adc8d16dc9d47223e961b662e28294f8
 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
@@ -684,7 +684,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P 0c53a4c2da31f91947f1347f1d33d0c83b843d26
-R 69a2575f1608bb2456de34d99c90c314
-U danielk1977
-Z a550b3819182c5fbaaf055096d0ff219
+P fc4f0621535e27eceb0b4b900a8c59dc06e84487
+R 89762139291a67475ddfc7f16b017b8d
+U drh
+Z b28b3f967fddc56af8e4e065924a72f1
index d9400aaacf4f04526cebfdec5af4dfb63430708b..51813470299cbf303cac07254fcc926128a00423 100644 (file)
@@ -1 +1 @@
-fc4f0621535e27eceb0b4b900a8c59dc06e84487
\ No newline at end of file
+d77a702358deddfa9987147999d06a235e730fa9
\ No newline at end of file
index 00788d3ddb5b4594f127dfecabd4548733482d95..56d07f8a4abe4bb4961273226a2747f4807ef33b 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.813 2008/12/21 03:51:16 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.814 2008/12/23 13:35:23 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1499,11 +1499,11 @@ struct SrcList {
     Select *pSelect;  /* A SELECT statement used in place of a table name */
     u8 isPopulated;   /* Temporary table associated with SELECT is populated */
     u8 jointype;      /* Type of join between this able and the previous */
+    u8 notIndexed;    /* True if there is a NOT INDEXED clause */
     int iCursor;      /* The VDBE cursor number used to access this table */
     Expr *pOn;        /* The ON clause of a join */
     IdList *pUsing;   /* The USING clause of a join */
     Bitmask colUsed;  /* Bit N (1<<N) set if column N or pTab is used */
-    u8 notIndexed;    /* True if there is a NOT INDEXED clause */
     char *zIndex;     /* Identifier from "INDEXED BY <zIndex>" clause */
     Index *pIndex;    /* Index structure corresponding to zIndex, if any */
   } a[1];             /* One entry for each identifier on the list */
index 48f89058d958c548f00e1bd36f840ea565cc6c37..f9a126ad3afac1670b735ad664bc9ea4a5c11977 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.805 2008/12/18 18:31:39 danielk1977 Exp $
+** $Id: vdbe.c,v 1.806 2008/12/23 13:35:23 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -4508,6 +4508,7 @@ case OP_RowSetRead: {       /* jump, out3 */
   assert( pOp->p1>0 && pOp->p1<=p->nMem );
   CHECK_FOR_INTERRUPT;
   pIdx = &p->aMem[pOp->p1];
+  pOut = &p->aMem[pOp->p3];
   if( (pIdx->flags & MEM_RowSet)==0 
    || sqlite3RowSetNext(pIdx->u.pRowSet, &val)==0
   ){
@@ -4517,7 +4518,6 @@ case OP_RowSetRead: {       /* jump, out3 */
   }else{
     /* A value was pulled from the index */
     assert( pOp->p3>0 && pOp->p3<=p->nMem );
-    pOut = &p->aMem[pOp->p3];
     sqlite3VdbeMemSetInt64(pOut, val);
   }
   break;
index f08ca56d063ef3c2d5aa6429446520f664f5a85d..1f6c0951f7f682ff1cfbe4ef66d3b287b32e083f 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.340 2008/12/21 03:51:16 drh Exp $
+** $Id: where.c,v 1.341 2008/12/23 13:35:23 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -142,7 +142,6 @@ struct WhereClause {
 struct WhereOrInfo {
   WhereClause wc;          /* Decomposition into subterms */
   Bitmask indexable;       /* Bitmask of all indexable tables in the clause */
-  WherePlan *aPlan;        /* Search plan for each subterm */
 };
 
 /*
@@ -268,7 +267,6 @@ static void whereClauseClear(WhereClause*);
 static void whereOrInfoDelete(sqlite3 *db, WhereOrInfo *p){
   if( p ){
     whereClauseClear(&p->wc);
-    sqlite3DbFree(db, p->aPlan);
     sqlite3DbFree(db, p);
   }
 }
@@ -826,7 +824,6 @@ static void exprAnalyzeOrTerm(
   pTerm->wtFlags |= TERM_ORINFO;
   pOrWc = &pOrInfo->wc;
   whereClauseInit(pOrWc, pWC->pParse, pMaskSet);
-  pOrInfo->aPlan = 0;
   whereSplit(pOrWc, pExpr, TK_OR);
   exprAnalyzeAll(pSrc, pOrWc);
   if( db->mallocFailed ) return;
@@ -962,12 +959,6 @@ static void exprAnalyzeOrTerm(
       pTerm->eOperator = 0;  /* case 1 trumps case 2 */
     }
   }
-
-  /* If case 2 applies, allocate space for pOrInfo->aPlan
-  */
-  if( pTerm->eOperator==WO_OR ){
-    pOrInfo->aPlan = sqlite3DbMallocRaw(db, pOrWc->nTerm*sizeof(WherePlan));
-  }
 }
 #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
 
@@ -1723,6 +1714,8 @@ static void bestIndex(
   int eqTermMask;             /* Mask of valid equality operators */
   double cost;                /* Cost of using pProbe */
   double nRow;                /* Estimated number of rows in result set */
+  int i;                      /* Loop counter */
+  Bitmask maskSrc;            /* Bitmask for the pSrc table */
 
   WHERETRACE(("bestIndex: tbl=%s notReady=%llx\n", pSrc->pTab->zName,notReady));
   pProbe = pSrc->pTab->pIndex;
@@ -1821,6 +1814,44 @@ static void bestIndex(
     }
   }
 
+#if SQLITE_ENABLE_MULTI_OR
+  /* Search for an OR-clause that can be used to look up the table.
+  */
+  maskSrc = getMask(pWC->pMaskSet, iCur);
+  for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
+    WhereClause tempWC;
+    tempWC = *pWC;
+    tempWC.nSlot = 1;
+    if( pTerm->eOperator==WO_OR 
+        && ((pTerm->prereqAll & ~maskSrc) & notReady)==0
+        && (pTerm->u.pOrInfo->indexable & maskSrc)!=0 ){
+      WhereClause *pOrWC = &pTerm->u.pOrInfo->wc;
+      WhereTerm *pOrTerm;
+      int j;
+      double rTotal = 0;
+      double nRow = 0;
+      for(j=0, pOrTerm=pOrWC->a; j<pOrWC->nTerm; j++, pOrTerm++){
+        WhereCost sTermCost;
+        if( pOrTerm->leftCursor!=iCur ) continue;
+        tempWC.a = pOrTerm;
+        bestIndex(pParse, &tempWC, pSrc, notReady, 0, &sTermCost);
+        if( sTermCost.plan.wsFlags==0 ){
+          rTotal = pCost->rCost;
+          break;
+        }
+        rTotal += sTermCost.rCost;
+        nRow += sTermCost.nRow;
+      }
+      if( rTotal<pCost->rCost ){
+        pCost->rCost = rTotal;
+        pCost->nRow = nRow;
+        pCost->plan.wsFlags = WHERE_MULTI_OR;
+        pCost->plan.u.pTerm = pTerm;
+      }
+    }
+  }
+#endif
+
   /* If the pSrc table is the right table of a LEFT JOIN then we may not
   ** use an index to satisfy IS NULL constraints on that table.  This is
   ** because columns might end up being NULL if the table does not match -
@@ -2529,7 +2560,10 @@ static Bitmask codeOneLoopStart(
     pLevel->p1 = iIdxCur;
     disableTerm(pLevel, pRangeStart);
     disableTerm(pLevel, pRangeEnd);
-  }else if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
+  }else
+
+#if SQLITE_ENABLE_MULTI_OR
+  if( pLevel->plan.wsFlags & WHERE_MULTI_OR ){
     /* Case 4:  Two or more separately indexed terms connected by OR
     **
     ** Example:
@@ -2562,6 +2596,7 @@ static Bitmask codeOneLoopStart(
     WhereTerm *pTerm;      /* The complete OR-clause */
     WhereClause *pOrWc;    /* The OR-clause broken out into subterms */
     WhereTerm *pOrTerm;    /* A single subterm within the OR-clause */
+    SrcList oneTab;        /* Shortened table list */
    
     pTerm = pLevel->plan.u.pTerm;
     assert( pTerm!=0 );
@@ -2570,12 +2605,22 @@ static Bitmask codeOneLoopStart(
     pOrWc = &pTerm->u.pOrInfo->wc;
     
     regRowset = sqlite3GetTempReg(pParse);
-    sqlite3VdbeAddOp1(v, OP_Null, regRowset);
+    regNextRowid = sqlite3GetTempReg(pParse);
+    sqlite3VdbeAddOp2(v, OP_Null, 0, regRowset);
+    oneTab.nSrc = 1;
+    oneTab.nAlloc = 1;
+    oneTab.a[0] = *pTabItem;
     for(j=0, pOrTerm=pOrWc->a; j<pOrWc->nTerm; j++, pOrTerm++){
+      WhereInfo *pSubWInfo;
       if( pOrTerm->leftCursor!=iCur ) continue;
-      /* fillRowSetFromIdx(pParse, regRowset, pTabItem, pOrTerm); */
+      pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0, 0);
+      if( pSubWInfo ){
+        sqlite3VdbeAddOp2(v, OP_Rowid, oneTab.a[0].iCursor, regNextRowid);
+        sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowset, regNextRowid);
+        pSubWInfo->a[0].plan.wsFlags |= WHERE_IDX_ONLY;
+        sqlite3WhereEnd(pSubWInfo);
+      }
     }
-    regNextRowid = sqlite3GetTempReg(pParse);
     sqlite3VdbeResolveLabel(v, addrCont);
     addrCont = 
        sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowset, addrBrk, regNextRowid);
@@ -2583,7 +2628,10 @@ static Bitmask codeOneLoopStart(
     sqlite3ReleaseTempReg(pParse, regNextRowid);
     pLevel->op = OP_Goto;
     pLevel->p2 = addrCont;
-  }else{
+  }else
+#endif /* SQLITE_ENABLE_MULTI_OR */
+
+  {
     /* Case 5:  There is no usable index.  We must do a complete
     **          scan of the entire table.
     */