Optimize WHERE clauses that constain AND, BETWEEN, and LIKE terms as operands

of an OR. (CVS 6068)

FossilOrigin-Name: 67cf24b30e087796cfb0fccf47328e72ade5ecdc
This commit is contained in:
drh 2008-12-28 18:35:08 +00:00
parent 6df2acd216
commit 294352578e
4 changed files with 61 additions and 20 deletions

View File

@ -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

View File

@ -1 +1 @@
fa95f843e179a38f663978d675607c4c3037928d
67cf24b30e087796cfb0fccf47328e72ade5ecdc

View 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);

View 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