1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-08 03:22:21 +03:00

Multi-index OR-clause optimization now works for simple tests. There are

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
This commit is contained in:
drh
2008-12-23 13:35:23 +00:00
parent 1f58153a9a
commit dd5f5a6231
5 changed files with 79 additions and 31 deletions

View File

@@ -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) 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-23T11:46:28 D 2008-12-23T13:35:23
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 77635d0909c2067cee03889a1e04ce910d8fb809 F Makefile.in 77635d0909c2067cee03889a1e04ce910d8fb809
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -158,7 +158,7 @@ F src/select.c a4316c5e8a417687e159b3d3ae689363d1dec5df
F src/shell.c 65d19f8996a160f288087e31810f24025439c62a F src/shell.c 65d19f8996a160f288087e31810f24025439c62a
F src/sqlite.h.in 065a828e299960316aa34f05b9f0f10f33afe4c8 F src/sqlite.h.in 065a828e299960316aa34f05b9f0f10f33afe4c8
F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17 F src/sqlite3ext.h 1db7d63ab5de4b3e6b83dd03d1a4e64fef6d2a17
F src/sqliteInt.h 24f71f7e2758516aa6b64e1f0ca02ee6e29344d3 F src/sqliteInt.h 9411acda2959c3494bafb1ac98048a53ee920ea3
F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8 F src/sqliteLimit.h f435e728c6b620ef7312814d660a81f9356eb5c8
F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76 F src/status.c 237b193efae0cf6ac3f0817a208de6c6c6ef6d76
F src/table.c 23db1e5f27c03160987c122a078b4bb51ef0b2f8 F src/table.c 23db1e5f27c03160987c122a078b4bb51ef0b2f8
@@ -198,7 +198,7 @@ F src/update.c 080889d241e4dcd1c545c8051eb6de86f4939295
F src/utf.c 1da9c832dba0fa8f865b5b902d93f420a1ee4245 F src/utf.c 1da9c832dba0fa8f865b5b902d93f420a1ee4245
F src/util.c ea62608f66f33a7e8322de83024ae37c415c0c7f F src/util.c ea62608f66f33a7e8322de83024ae37c415c0c7f
F src/vacuum.c 383d6297bddc011ab04a9eed110db6eaf523e8e9 F src/vacuum.c 383d6297bddc011ab04a9eed110db6eaf523e8e9
F src/vdbe.c e9a7825d25496343937852fa70b993ee217f924e F src/vdbe.c fb84f5ce769c74348d808cdc6fbba91aec54fe30
F src/vdbe.h 03516f28bf5aca00a53c4dccd6c313f96adb94f6 F src/vdbe.h 03516f28bf5aca00a53c4dccd6c313f96adb94f6
F src/vdbeInt.h e6e80a99ce634983b7cc2498843b4d2e5540900a F src/vdbeInt.h e6e80a99ce634983b7cc2498843b4d2e5540900a
F src/vdbeapi.c 85c33cfbfa56249cbe627831610afafba754477d F src/vdbeapi.c 85c33cfbfa56249cbe627831610afafba754477d
@@ -207,7 +207,7 @@ F src/vdbeblob.c b0dcebfafedcf9c0addc7901ad98f6f986c08935
F src/vdbemem.c f9c859ac17e2e05a0f249868ce4f191f69edd31d F src/vdbemem.c f9c859ac17e2e05a0f249868ce4f191f69edd31d
F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43 F src/vtab.c e39e011d7443a8d574b1b9cde207a35522e6df43
F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d F src/walker.c 488c2660e13224ff70c0c82761118efb547f8f0d
F src/where.c 6e5de2421da8d9ed62a2fcf7df70df8301282936 F src/where.c 50e47032adc8d16dc9d47223e961b662e28294f8
F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617 F tclinstaller.tcl 4356d9d94d2b5ed5e68f9f0c80c4df3048dd7617
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911 F test/alias.test 597662c5d777a122f9a3df0047ea5c5bd383a911
@@ -684,7 +684,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
P 0c53a4c2da31f91947f1347f1d33d0c83b843d26 P fc4f0621535e27eceb0b4b900a8c59dc06e84487
R 69a2575f1608bb2456de34d99c90c314 R 89762139291a67475ddfc7f16b017b8d
U danielk1977 U drh
Z a550b3819182c5fbaaf055096d0ff219 Z b28b3f967fddc56af8e4e065924a72f1

View File

@@ -1 +1 @@
fc4f0621535e27eceb0b4b900a8c59dc06e84487 d77a702358deddfa9987147999d06a235e730fa9

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** 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_ #ifndef _SQLITEINT_H_
#define _SQLITEINT_H_ #define _SQLITEINT_H_
@@ -1499,11 +1499,11 @@ struct SrcList {
Select *pSelect; /* A SELECT statement used in place of a table name */ Select *pSelect; /* A SELECT statement used in place of a table name */
u8 isPopulated; /* Temporary table associated with SELECT is populated */ u8 isPopulated; /* Temporary table associated with SELECT is populated */
u8 jointype; /* Type of join between this able and the previous */ 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 */ int iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */ Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING 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 */ 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 */ char *zIndex; /* Identifier from "INDEXED BY <zIndex>" clause */
Index *pIndex; /* Index structure corresponding to zIndex, if any */ Index *pIndex; /* Index structure corresponding to zIndex, if any */
} a[1]; /* One entry for each identifier on the list */ } a[1]; /* One entry for each identifier on the list */

View File

@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** 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 "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -4508,6 +4508,7 @@ case OP_RowSetRead: { /* jump, out3 */
assert( pOp->p1>0 && pOp->p1<=p->nMem ); assert( pOp->p1>0 && pOp->p1<=p->nMem );
CHECK_FOR_INTERRUPT; CHECK_FOR_INTERRUPT;
pIdx = &p->aMem[pOp->p1]; pIdx = &p->aMem[pOp->p1];
pOut = &p->aMem[pOp->p3];
if( (pIdx->flags & MEM_RowSet)==0 if( (pIdx->flags & MEM_RowSet)==0
|| sqlite3RowSetNext(pIdx->u.pRowSet, &val)==0 || sqlite3RowSetNext(pIdx->u.pRowSet, &val)==0
){ ){
@@ -4517,7 +4518,6 @@ case OP_RowSetRead: { /* jump, out3 */
}else{ }else{
/* A value was pulled from the index */ /* A value was pulled from the index */
assert( pOp->p3>0 && pOp->p3<=p->nMem ); assert( pOp->p3>0 && pOp->p3<=p->nMem );
pOut = &p->aMem[pOp->p3];
sqlite3VdbeMemSetInt64(pOut, val); sqlite3VdbeMemSetInt64(pOut, val);
} }
break; break;

View File

@@ -16,7 +16,7 @@
** so is applicable. Because this module is responsible for selecting ** so is applicable. Because this module is responsible for selecting
** indices, you might also think of this module as the "query optimizer". ** 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" #include "sqliteInt.h"
@@ -142,7 +142,6 @@ struct WhereClause {
struct WhereOrInfo { struct WhereOrInfo {
WhereClause wc; /* Decomposition into subterms */ WhereClause wc; /* Decomposition into subterms */
Bitmask indexable; /* Bitmask of all indexable tables in the clause */ 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){ static void whereOrInfoDelete(sqlite3 *db, WhereOrInfo *p){
if( p ){ if( p ){
whereClauseClear(&p->wc); whereClauseClear(&p->wc);
sqlite3DbFree(db, p->aPlan);
sqlite3DbFree(db, p); sqlite3DbFree(db, p);
} }
} }
@@ -826,7 +824,6 @@ static void exprAnalyzeOrTerm(
pTerm->wtFlags |= TERM_ORINFO; pTerm->wtFlags |= TERM_ORINFO;
pOrWc = &pOrInfo->wc; pOrWc = &pOrInfo->wc;
whereClauseInit(pOrWc, pWC->pParse, pMaskSet); whereClauseInit(pOrWc, pWC->pParse, pMaskSet);
pOrInfo->aPlan = 0;
whereSplit(pOrWc, pExpr, TK_OR); whereSplit(pOrWc, pExpr, TK_OR);
exprAnalyzeAll(pSrc, pOrWc); exprAnalyzeAll(pSrc, pOrWc);
if( db->mallocFailed ) return; if( db->mallocFailed ) return;
@@ -962,12 +959,6 @@ static void exprAnalyzeOrTerm(
pTerm->eOperator = 0; /* case 1 trumps case 2 */ 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 */ #endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
@@ -1723,6 +1714,8 @@ static void bestIndex(
int eqTermMask; /* Mask of valid equality operators */ int eqTermMask; /* Mask of valid equality operators */
double cost; /* Cost of using pProbe */ double cost; /* Cost of using pProbe */
double nRow; /* Estimated number of rows in result set */ 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)); WHERETRACE(("bestIndex: tbl=%s notReady=%llx\n", pSrc->pTab->zName,notReady));
pProbe = pSrc->pTab->pIndex; 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 /* 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 ** 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 - ** because columns might end up being NULL if the table does not match -
@@ -2529,7 +2560,10 @@ static Bitmask codeOneLoopStart(
pLevel->p1 = iIdxCur; pLevel->p1 = iIdxCur;
disableTerm(pLevel, pRangeStart); disableTerm(pLevel, pRangeStart);
disableTerm(pLevel, pRangeEnd); 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 /* Case 4: Two or more separately indexed terms connected by OR
** **
** Example: ** Example:
@@ -2562,6 +2596,7 @@ static Bitmask codeOneLoopStart(
WhereTerm *pTerm; /* The complete OR-clause */ WhereTerm *pTerm; /* The complete OR-clause */
WhereClause *pOrWc; /* The OR-clause broken out into subterms */ WhereClause *pOrWc; /* The OR-clause broken out into subterms */
WhereTerm *pOrTerm; /* A single subterm within the OR-clause */ WhereTerm *pOrTerm; /* A single subterm within the OR-clause */
SrcList oneTab; /* Shortened table list */
pTerm = pLevel->plan.u.pTerm; pTerm = pLevel->plan.u.pTerm;
assert( pTerm!=0 ); assert( pTerm!=0 );
@@ -2570,12 +2605,22 @@ static Bitmask codeOneLoopStart(
pOrWc = &pTerm->u.pOrInfo->wc; pOrWc = &pTerm->u.pOrInfo->wc;
regRowset = sqlite3GetTempReg(pParse); regRowset = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp1(v, OP_Null, regRowset);
for(j=0, pOrTerm=pOrWc->a; j<pOrWc->nTerm; j++, pOrTerm++){
if( pOrTerm->leftCursor!=iCur ) continue;
/* fillRowSetFromIdx(pParse, regRowset, pTabItem, pOrTerm); */
}
regNextRowid = sqlite3GetTempReg(pParse); 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;
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);
}
}
sqlite3VdbeResolveLabel(v, addrCont); sqlite3VdbeResolveLabel(v, addrCont);
addrCont = addrCont =
sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowset, addrBrk, regNextRowid); sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowset, addrBrk, regNextRowid);
@@ -2583,7 +2628,10 @@ static Bitmask codeOneLoopStart(
sqlite3ReleaseTempReg(pParse, regNextRowid); sqlite3ReleaseTempReg(pParse, regNextRowid);
pLevel->op = OP_Goto; pLevel->op = OP_Goto;
pLevel->p2 = addrCont; pLevel->p2 = addrCont;
}else{ }else
#endif /* SQLITE_ENABLE_MULTI_OR */
{
/* Case 5: There is no usable index. We must do a complete /* Case 5: There is no usable index. We must do a complete
** scan of the entire table. ** scan of the entire table.
*/ */