mirror of https://github.com/sqlite/sqlite
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:
parent
6df2acd216
commit
294352578e
14
manifest
14
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
|
||||
|
|
|
@ -1 +1 @@
|
|||
fa95f843e179a38f663978d675607c4c3037928d
|
||||
67cf24b30e087796cfb0fccf47328e72ade5ecdc
|
52
src/where.c
52
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.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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue