]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Optimize WHERE clauses that constain AND, BETWEEN, and LIKE terms as operands
authordrh <drh@noemail.net>
Sun, 28 Dec 2008 18:35:08 +0000 (18:35 +0000)
committerdrh <drh@noemail.net>
Sun, 28 Dec 2008 18:35:08 +0000 (18:35 +0000)
of an OR. (CVS 6068)

FossilOrigin-Name: 67cf24b30e087796cfb0fccf47328e72ade5ecdc

manifest
manifest.uuid
src/where.c
test/where7.test

index 2877586851237085ca105dab79ef36da1c06d05d..748a7cf804050de1035b3c5c42b3edd6dab09239 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Simplify\sthe\sVM\scode\sthat\simplements\sWHERE\sclaues.\s(CVS\s6067)
-D 2008-12-28T16:55:25
+C Optimize\sWHERE\sclauses\sthat\sconstain\sAND,\sBETWEEN,\sand\sLIKE\sterms\sas\soperands\nof\san\sOR.\s(CVS\s6068)
+D 2008-12-28T18:35:09
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 77635d0909c2067cee03889a1e04ce910d8fb809
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -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 f41330e71f3dde12cc6631ae9f75c9869b92c32b
+F src/where.c 4050b918a379e23d5b645d888b91dba2e7c469a9
 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
@@ -655,7 +655,7 @@ F test/where3.test 97d3936e6a443b968f1a61cdcc0f673252000e94
 F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
 F test/where6.test 42c4373595f4409d9c6a9987b4a60000ad664faf
-F test/where7.test b04da5cee08a573c120c95781d7413a7e25ac8d5
+F test/where7.test c27e4865d69b35dc21b4cbff097cf02e9cdc9950
 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
 F test/zeroblob.test 792124852ec61458a2eb527b5091791215e0be95
 F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
@@ -686,7 +686,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P 08352f9ea9d2a1759320efc46e418079000855cb
-R b27114cf38ee45f9d895c0015e5cf61b
+P fa95f843e179a38f663978d675607c4c3037928d
+R 7f2475a8de47b6500bdb0400363621d0
 U drh
-Z 5701aac5e9c50a29a7e1c4535e66ab21
+Z 2bf13b04bd3fbd90db56a109bb7f3eb1
index dcd41005a3a12a72151b414ac27fd9cfc15d295b..13953d7e4c09ab06ebc8561876975eb8536d27c2 100644 (file)
@@ -1 +1 @@
-fa95f843e179a38f663978d675607c4c3037928d
\ No newline at end of file
+67cf24b30e087796cfb0fccf47328e72ade5ecdc
\ No newline at end of file
index d0a5c531e8bcad531a4fb265902181cace0cc611..795b2e05509b4a377606c33e52fafb83ca5d0dfa 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.345 2008/12/28 16:55:25 drh Exp $
+** $Id: where.c,v 1.346 2008/12/28 18:35:09 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -129,6 +129,7 @@ struct WhereTerm {
 struct WhereClause {
   Parse *pParse;           /* The parser context */
   WhereMaskSet *pMaskSet;  /* Mapping of table cursor numbers to bitmasks */
+  u8 op;                   /* Split operator.  TK_AND or TK_OR */
   int nTerm;               /* Number of terms */
   int nSlot;               /* Number of entries in a[] */
   WhereTerm *a;            /* Each a[] describes a term of the WHERE cluase */
@@ -149,9 +150,7 @@ struct WhereOrInfo {
 ** a dynamically allocated instance of the following structure.
 */
 struct WhereAndInfo {
-  WhereClause wc;          /* The OR subexpression broken out */
-  Index *pIdx;             /* Index to use */
-  double cost;             /* Cost of evaluating this OR subexpression */
+  WhereClause wc;          /* The subexpression broken out */
 };
 
 /*
@@ -369,6 +368,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, u8 wtFlags){
 ** all terms of the WHERE clause.
 */
 static void whereSplit(WhereClause *pWC, Expr *pExpr, int op){
+  pWC->op = (u8)op;
   if( pExpr==0 ) return;
   if( pExpr->op!=op ){
     whereClauseInsert(pWC, pExpr, 0);
@@ -835,8 +835,30 @@ static void exprAnalyzeOrTerm(
   indexable = chngToIN = ~(Bitmask)0;
   for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
     if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
+      WhereAndInfo *pAndInfo;
+      assert( pOrTerm->eOperator==0 );
+      assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
       chngToIN = 0;
-      indexable = 0;   /***** FIX ME.  Some AND clauses are indexable. */
+      pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
+      if( pAndInfo ){
+        WhereClause *pAndWC;
+        WhereTerm *pAndTerm;
+        int j;
+        Bitmask b = 0;
+        pOrTerm->u.pAndInfo = pAndInfo;
+        pOrTerm->wtFlags |= TERM_ANDINFO;
+        pOrTerm->eOperator = WO_AND;
+        pAndWC = &pAndInfo->wc;
+        whereClauseInit(pAndWC, pWC->pParse, pMaskSet);
+        whereSplit(pAndWC, pOrTerm->pExpr, TK_AND);
+        exprAnalyzeAll(pSrc, pAndWC);
+        for(j=0, pAndTerm=pAndWC->a; j<pAndWC->nTerm; j++, pAndTerm++){
+          if( pAndTerm->pExpr && allowedOp(pAndTerm->pExpr->op) ){
+            b |= getMask(pMaskSet, pAndTerm->leftCursor);
+          }
+        }
+        indexable &= b;
+      }
     }else if( pOrTerm->wtFlags & TERM_COPIED ){
       /* Skip this term for now.  We revisit it when we process the
       ** corresponding TERM_VIRTUAL term */
@@ -1082,7 +1104,7 @@ static void exprAnalyze(
   ** skipped.  Or, if the children are satisfied by an index, the original
   ** BETWEEN term is skipped.
   */
-  else if( pExpr->op==TK_BETWEEN ){
+  else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){
     ExprList *pList = pExpr->pList;
     int i;
     static const u8 ops[] = {TK_GE, TK_LE};
@@ -1108,6 +1130,7 @@ static void exprAnalyze(
   ** an OR operator.
   */
   else if( pExpr->op==TK_OR ){
+    assert( pWC->op==TK_AND );
     exprAnalyzeOrTerm(pSrc, pWC, idxTerm);
   }
 #endif /* SQLITE_OMIT_OR_OPTIMIZATION */
@@ -1123,7 +1146,8 @@ static void exprAnalyze(
   ** The last character of the prefix "abc" is incremented to form the
   ** termination condition "abd".
   */
-  if( isLikeOrGlob(pParse, pExpr, &nPattern, &isComplete, &noCase) ){
+  if( isLikeOrGlob(pParse, pExpr, &nPattern, &isComplete, &noCase)
+         && pWC->op==TK_AND ){
     Expr *pLeft, *pRight;
     Expr *pStr1, *pStr2;
     Expr *pNewExpr1, *pNewExpr2;
@@ -1832,9 +1856,15 @@ static void bestIndex(
       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( pOrTerm->eOperator==WO_AND ){
+          WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc;
+          bestIndex(pParse, pAndWC, pSrc, notReady, 0, &sTermCost);
+        }else if( pOrTerm->leftCursor==iCur ){
+          tempWC.a = pOrTerm;
+          bestIndex(pParse, &tempWC, pSrc, notReady, 0, &sTermCost);
+        }else{
+          continue;
+        }
         if( sTermCost.plan.wsFlags==0 ){
           rTotal = pCost->rCost;
           break;
@@ -2670,7 +2700,7 @@ static Bitmask codeOneLoopStart(
     oneTab.a[0] = *pTabItem;
     for(j=0, pOrTerm=pOrWc->a; j<pOrWc->nTerm; j++, pOrTerm++){
       WhereInfo *pSubWInfo;
-      if( pOrTerm->leftCursor!=iCur ) continue;
+      if( pOrTerm->leftCursor!=iCur && pOrTerm->eOperator!=WO_AND ) continue;
       pSubWInfo = sqlite3WhereBegin(pParse, &oneTab, pOrTerm->pExpr, 0,
                         WHERE_FILL_ROWSET | WHERE_OMIT_OPEN | WHERE_OMIT_CLOSE,
                         regOrRowset);
index e7ca4f73d679d8eec20777d064d5725e098dc06e..a7686220e86a9a87e33923e2e0693bff7f231c28 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the multi-index OR clause optimizer.
 #
-# $Id: where7.test,v 1.1 2008/12/23 23:56:22 drh Exp $
+# $Id: where7.test,v 1.2 2008/12/28 18:35:09 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -89,6 +89,17 @@ do_test where7-1.10 {
     SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4 OR b>10)
   }
 } {2 4 5 scan 0}
+do_test where7-1.11 {
+  count_steps {
+    SELECT a FROM t1 WHERE (d=5 AND b=3) OR c==100;
+  }
+} {2 5 scan 0}
+do_test where7-1.12 {
+breakpoint
+  count_steps {
+    SELECT a FROM t1 WHERE (b BETWEEN 2 AND 4) OR c=100
+  }
+} {1 2 3 5 scan 0}
 
 
 finish_test