Make use of covering indexes in the OR optimization.
FossilOrigin-Name: 9de3d7123007636aa97da1c70bc34344b0391078
This commit is contained in:
commit
8ea0056d5c
24
manifest
24
manifest
@ -1,5 +1,5 @@
|
||||
C Avoid\sunnecessary\sWHERE\sclause\sterm\stests\swhen\scoding\sa\sjoin\swhere\sone\sof\sthe\stables\scontains\sa\sOR\sconstraint.
|
||||
D 2016-01-29T18:11:04.923
|
||||
C Make\suse\sof\scovering\sindexes\sin\sthe\sOR\soptimization.
|
||||
D 2016-01-30T02:10:38.644
|
||||
F Makefile.in 027c1603f255390c43a426671055a31c0a65fdb4
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 72b7858f02017611c3ac1ddc965251017fed0845
|
||||
@ -347,7 +347,7 @@ F src/printf.c af589a27b7d40f6f4f704e9eea99f02f18ad6d32
|
||||
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c 9f7ce3a3c087afb7597b7c916c99126ff3f12f0c
|
||||
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
|
||||
F src/select.c c34292c8ce7fe69c7cf890d933834a22572bd301
|
||||
F src/select.c ea6f3b0c279aa37eb3701792d094673a7ad1bf88
|
||||
F src/shell.c dcd7a83645ef2a58ee9c6d0ea4714d877d7835c4
|
||||
F src/sqlite.h.in 214476a62012e578f42133a9a3b4f97a9aa421a3
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
@ -412,11 +412,11 @@ F src/update.c 17332f9fe818cbc0444c36a811800af8498af4c3
|
||||
F src/utf.c 32d7f82aa921322f3e1c956f4b58f019ebd2c6b3
|
||||
F src/util.c 72d40df0a52d3f30b462a15f0e094fcbade6dc82
|
||||
F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701
|
||||
F src/vdbe.c 3ffbcc413bf793e3f0b95b79ef2f4bd449a5b5a3
|
||||
F src/vdbe.c 0686ef5ee103935548d1aa2c0c28e52f1ae6e5a8
|
||||
F src/vdbe.h 7a733ea8aac1b77305a67698e784fa3484ee3337
|
||||
F src/vdbeInt.h 42eefa4f9e7432b9968d321b44e48821ec13b189
|
||||
F src/vdbeInt.h 171fdc5f6af4eeb0ff0559dbf0a71244d726a670
|
||||
F src/vdbeapi.c ffae8f5af4570fbd548504e815e9fb7227f0822e
|
||||
F src/vdbeaux.c fc8926c4232cd5c982f36197b1443212f265d927
|
||||
F src/vdbeaux.c 108124021ed02fa4fc6f90a53dcaf58ac3bab941
|
||||
F src/vdbeblob.c 37c3d11a753e403698c69e17383d282e1ae73e75
|
||||
F src/vdbemem.c b9181e77eca2a095929d46250daf85c8d2621fc0
|
||||
F src/vdbesort.c ef3c6d1f1a7d44cf67bb2bee59ea3d1fe5bad174
|
||||
@ -428,7 +428,7 @@ F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c
|
||||
F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
|
||||
F src/where.c af9bf5dcec1a0e52726c550924aa91d837166251
|
||||
F src/whereInt.h 78b6b4de94db84aecbdc07fe3e38f648eb391e9a
|
||||
F src/wherecode.c 22a7fee2360c738533ce12615f487594849adc78
|
||||
F src/wherecode.c 3c4757ae85e8237808a4ec1a25c513d83e1395e0
|
||||
F src/whereexpr.c 197a448b52073aee43eca3a2233fc113369eb2d4
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
@ -1334,7 +1334,7 @@ F test/where9.test 729c3ba9b47e8f9f1aab96bae7dad2a524f1d1a2
|
||||
F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
|
||||
F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
|
||||
F test/whereC.test cae295158703cb3fc23bf1a108a9ab730efff0f6
|
||||
F test/whereD.test 9eba1f9b18e5b19a0b0bcaae5e8c037260195f2b
|
||||
F test/whereD.test 51366b07cb6f546cd30cc803f7e754f063b940de
|
||||
F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f
|
||||
F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
||||
F test/whereG.test dde4c52a97385a55be6a7cd46be8373f0cf35501
|
||||
@ -1422,8 +1422,8 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 2910ef64097b890c9f8929bf609ea2827db7ac97 ab94603974a0ad5342e5aee27603162652e70492
|
||||
R a5e195d58a480f7623421e36c529b8b4
|
||||
T +closed ab94603974a0ad5342e5aee27603162652e70492
|
||||
P 512caa1ad30e6f699e2d006d5ab7674d55d2c746 6c520d5726e80b4251338c43c405270d150ea81e
|
||||
R e4149e0b983ab1835709b124e27b8f90
|
||||
T +closed 6c520d5726e80b4251338c43c405270d150ea81e
|
||||
U drh
|
||||
Z e540fd89ce55e7aa63a8bd5d9b52b2c8
|
||||
Z 625eb895cdbe3aba3d382c8d078d5321
|
||||
|
@ -1 +1 @@
|
||||
512caa1ad30e6f699e2d006d5ab7674d55d2c746
|
||||
9de3d7123007636aa97da1c70bc34344b0391078
|
@ -2870,10 +2870,11 @@ static int multiSelectOrderBy(
|
||||
** to the right and the left are evaluated, they use the correct
|
||||
** collation.
|
||||
*/
|
||||
aPermute = sqlite3DbMallocRaw(db, sizeof(int)*nOrderBy);
|
||||
aPermute = sqlite3DbMallocRaw(db, sizeof(int)*(nOrderBy + 1));
|
||||
if( aPermute ){
|
||||
struct ExprList_item *pItem;
|
||||
for(i=0, pItem=pOrderBy->a; i<nOrderBy; i++, pItem++){
|
||||
aPermute[0] = nOrderBy;
|
||||
for(i=1, pItem=pOrderBy->a; i<=nOrderBy; i++, pItem++){
|
||||
assert( pItem->u.x.iOrderByCol>0 );
|
||||
assert( pItem->u.x.iOrderByCol<=p->pEList->nExpr );
|
||||
aPermute[i] = pItem->u.x.iOrderByCol - 1;
|
||||
|
25
src/vdbe.c
25
src/vdbe.c
@ -2067,11 +2067,14 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
|
||||
** The permutation is only valid until the next OP_Compare that has
|
||||
** the OPFLAG_PERMUTE bit set in P5. Typically the OP_Permutation should
|
||||
** occur immediately prior to the OP_Compare.
|
||||
**
|
||||
** The first integer in the P4 integer array is the length of the array
|
||||
** and does not become part of the permutation.
|
||||
*/
|
||||
case OP_Permutation: {
|
||||
assert( pOp->p4type==P4_INTARRAY );
|
||||
assert( pOp->p4.ai );
|
||||
aPermute = pOp->p4.ai;
|
||||
aPermute = pOp->p4.ai + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2376,12 +2379,16 @@ case OP_Column: {
|
||||
u32 t; /* A type code from the record header */
|
||||
Mem *pReg; /* PseudoTable input register */
|
||||
|
||||
pC = p->apCsr[pOp->p1];
|
||||
p2 = pOp->p2;
|
||||
|
||||
/* If the cursor cache is stale, bring it up-to-date */
|
||||
rc = sqlite3VdbeCursorMoveto(&pC, &p2);
|
||||
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( p2<pC->nField );
|
||||
aOffset = pC->aOffset;
|
||||
@ -2390,8 +2397,6 @@ case OP_Column: {
|
||||
assert( pC->eCurType!=CURTYPE_SORTER );
|
||||
pCrsr = pC->uc.pCursor;
|
||||
|
||||
/* If the cursor cache is stale, bring it up-to-date */
|
||||
rc = sqlite3VdbeCursorMoveto(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( pC->cacheStatus!=p->cacheCtr ){
|
||||
if( pC->nullRow ){
|
||||
@ -3846,7 +3851,7 @@ seek_not_found:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Seek P1 P2 * * *
|
||||
/* Opcode: Seek P1 P2 P3 P4 *
|
||||
** Synopsis: intkey=r[P2]
|
||||
**
|
||||
** P1 is an open table cursor and P2 is a rowid integer. Arrange
|
||||
@ -3855,6 +3860,13 @@ seek_not_found:
|
||||
** This is actually a deferred seek. Nothing actually happens until
|
||||
** the cursor is used to read a record. That way, if no reads
|
||||
** occur, no unnecessary I/O happens.
|
||||
**
|
||||
** P4 may contain an array of integers (type P4_INTARRAY) containing
|
||||
** one entry for each column in the table P1 is open on. If so, then
|
||||
** parameter P3 is a cursor open on a database index. If array entry
|
||||
** a[i] is non-zero, then reading column (a[i]-1) from cursor P3 is
|
||||
** equivalent to performing the deferred seek and then reading column i
|
||||
** from P1.
|
||||
*/
|
||||
case OP_Seek: { /* in2 */
|
||||
VdbeCursor *pC;
|
||||
@ -3869,6 +3881,9 @@ case OP_Seek: { /* in2 */
|
||||
pIn2 = &aMem[pOp->p2];
|
||||
pC->movetoTarget = sqlite3VdbeIntValue(pIn2);
|
||||
pC->deferredMoveto = 1;
|
||||
assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 );
|
||||
pC->aAltMap = pOp->p4.ai;
|
||||
pC->pAltCursor = p->apCsr[pOp->p3];
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,7 @@ typedef struct AuxData AuxData;
|
||||
** * A virtual table
|
||||
** * A one-row "pseudotable" stored in a single register
|
||||
*/
|
||||
typedef struct VdbeCursor VdbeCursor;
|
||||
struct VdbeCursor {
|
||||
u8 eCurType; /* One of the CURTYPE_* values above */
|
||||
i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
|
||||
@ -100,6 +101,8 @@ struct VdbeCursor {
|
||||
int seekResult; /* Result of previous sqlite3BtreeMoveto() */
|
||||
i64 seqCount; /* Sequence counter */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
VdbeCursor *pAltCursor; /* Associated index cursor from which to read */
|
||||
int *aAltMap; /* Mapping from table to index column numbers */
|
||||
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
|
||||
u64 maskUsed; /* Mask of columns used by this cursor */
|
||||
#endif
|
||||
@ -124,7 +127,6 @@ struct VdbeCursor {
|
||||
** static element declared in the structure. nField total array slots for
|
||||
** aType[] and nField+1 array slots for aOffset[] */
|
||||
};
|
||||
typedef struct VdbeCursor VdbeCursor;
|
||||
|
||||
/*
|
||||
** When a sub-program is executed (OP_Program), a structure of this type
|
||||
@ -423,7 +425,7 @@ struct Vdbe {
|
||||
void sqlite3VdbeError(Vdbe*, const char *, ...);
|
||||
void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
|
||||
void sqliteVdbePopStack(Vdbe*,int);
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor*);
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
|
||||
int sqlite3VdbeCursorRestore(VdbeCursor*);
|
||||
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
||||
void sqlite3VdbePrintOp(FILE*, int, Op*);
|
||||
|
@ -1288,7 +1288,21 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
}
|
||||
#endif
|
||||
case P4_INTARRAY: {
|
||||
sqlite3_snprintf(nTemp, zTemp, "intarray");
|
||||
int i, j;
|
||||
int *ai = pOp->p4.ai;
|
||||
int n = ai[0]; /* The first element of an INTARRAY is always the
|
||||
** count of the number of elements to follow */
|
||||
zTemp[0] = '[';
|
||||
for(i=j=1; i<n && j<nTemp-7; i++){
|
||||
if( j>1 ) zTemp[j++] = ',';
|
||||
sqlite3_snprintf(nTemp-j, zTemp+j, "%d", ai[i]);
|
||||
j += sqlite3Strlen30(zTemp+j);
|
||||
}
|
||||
if( i<n ){
|
||||
memcpy(zTemp+j, ",...]", 6);
|
||||
}else{
|
||||
memcpy(zTemp+j, "]", 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case P4_SUBPROGRAM: {
|
||||
@ -3008,9 +3022,16 @@ int sqlite3VdbeCursorRestore(VdbeCursor *p){
|
||||
** If the cursor is already pointing to the correct row and that row has
|
||||
** not been deleted out from under the cursor, then this routine is a no-op.
|
||||
*/
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor *p){
|
||||
int sqlite3VdbeCursorMoveto(VdbeCursor **pp, int *piCol){
|
||||
VdbeCursor *p = *pp;
|
||||
if( p->eCurType==CURTYPE_BTREE ){
|
||||
if( p->deferredMoveto ){
|
||||
int iMap;
|
||||
if( p->aAltMap && (iMap = p->aAltMap[1+*piCol])>0 ){
|
||||
*pp = p->pAltCursor;
|
||||
*piCol = iMap - 1;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return handleDeferredMoveto(p);
|
||||
}
|
||||
if( sqlite3BtreeCursorHasMoved(p->uc.pCursor) ){
|
||||
|
@ -746,6 +746,55 @@ static void codeCursorHint(
|
||||
# define codeCursorHint(A,B,C) /* No-op */
|
||||
#endif /* SQLITE_ENABLE_CURSOR_HINTS */
|
||||
|
||||
/*
|
||||
** Cursor iCur is open on an intkey b-tree (a table). Register iRowid contains
|
||||
** a rowid value just read from cursor iIdxCur, open on index pIdx. This
|
||||
** function generates code to do a deferred seek of cursor iCur to the
|
||||
** rowid stored in register iRowid.
|
||||
**
|
||||
** Normally, this is just:
|
||||
**
|
||||
** OP_Seek $iCur $iRowid
|
||||
**
|
||||
** However, if the scan currently being coded is a branch of an OR-loop and
|
||||
** the statement currently being coded is a SELECT, then P3 of the OP_Seek
|
||||
** is set to iIdxCur and P4 is set to point to an array of integers
|
||||
** containing one entry for each column of the table cursor iCur is open
|
||||
** on. For each table column, if the column is the i'th column of the
|
||||
** index, then the corresponding array entry is set to (i+1). If the column
|
||||
** does not appear in the index at all, the array entry is set to 0.
|
||||
*/
|
||||
static void codeDeferredSeek(
|
||||
WhereInfo *pWInfo, /* Where clause context */
|
||||
Index *pIdx, /* Index scan is using */
|
||||
int iCur, /* Cursor for IPK b-tree */
|
||||
int iRowid, /* Register containing rowid to seek to */
|
||||
int iIdxCur /* Index cursor */
|
||||
){
|
||||
Parse *pParse = pWInfo->pParse; /* Parse context */
|
||||
Vdbe *v = pParse->pVdbe; /* Vdbe to generate code within */
|
||||
|
||||
assert( iIdxCur>0 );
|
||||
assert( pIdx->aiColumn[pIdx->nColumn-1]==-1 );
|
||||
|
||||
sqlite3VdbeAddOp3(v, OP_Seek, iCur, iRowid, iIdxCur);
|
||||
if( (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)
|
||||
&& sqlite3ParseToplevel(pParse)->writeMask==0
|
||||
){
|
||||
int i;
|
||||
Table *pTab = pIdx->pTable;
|
||||
int *ai = (int*)sqlite3DbMallocZero(pParse->db, sizeof(int)*(pTab->nCol+1));
|
||||
if( ai ){
|
||||
ai[0] = pTab->nCol;
|
||||
for(i=0; i<pIdx->nColumn-1; i++){
|
||||
assert( pIdx->aiColumn[i]<pTab->nCol );
|
||||
if( pIdx->aiColumn[i]>=0 ) ai[pIdx->aiColumn[i]+1] = i+1;
|
||||
}
|
||||
sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code for the start of the iLevel-th loop in the WHERE clause
|
||||
** implementation described by pWInfo.
|
||||
@ -1232,7 +1281,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, iRowidReg);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */
|
||||
codeDeferredSeek(pWInfo, pIdx, iCur, iRowidReg, iIdxCur);
|
||||
}
|
||||
}else if( iCur!=iIdxCur ){
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable);
|
||||
|
@ -156,7 +156,7 @@ do_searchcount_test 3.4.4 {
|
||||
|
||||
do_searchcount_test 3.5.1 {
|
||||
SELECT a, b FROM t3 WHERE (a=1 AND b='one') OR rowid=4
|
||||
} {1 one 2 two search 3}
|
||||
} {1 one 2 two search 2}
|
||||
do_searchcount_test 3.5.2 {
|
||||
SELECT a, c FROM t3 WHERE (a=1 AND b='one') OR rowid=4
|
||||
} {1 i 2 ii search 3}
|
||||
@ -271,5 +271,70 @@ do_execsql_test 5.3 {
|
||||
c16=1 or c17=1;
|
||||
} {1 {} {} {} {} {} {} {} {} {} {} {} {} {} {} 1 {} {}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
do_execsql_test 6.1 {
|
||||
CREATE TABLE x1(a, b, c, d, e);
|
||||
CREATE INDEX x1a ON x1(a);
|
||||
CREATE INDEX x1bc ON x1(b, c);
|
||||
CREATE INDEX x1cd ON x1(c, d);
|
||||
|
||||
INSERT INTO x1 VALUES(1, 2, 3, 4, 'A');
|
||||
INSERT INTO x1 VALUES(5, 6, 7, 8, 'B');
|
||||
INSERT INTO x1 VALUES(9, 10, 11, 12, 'C');
|
||||
INSERT INTO x1 VALUES(13, 14, 15, 16, 'D');
|
||||
}
|
||||
|
||||
do_searchcount_test 6.2.1 {
|
||||
SELECT e FROM x1 WHERE b=2 OR c=7;
|
||||
} {A B search 6}
|
||||
do_searchcount_test 6.2.2 {
|
||||
SELECT c FROM x1 WHERE b=2 OR c=7;
|
||||
} {3 7 search 4}
|
||||
|
||||
do_searchcount_test 6.3.1 {
|
||||
SELECT e FROM x1 WHERE a=1 OR b=10;
|
||||
} {A C search 6}
|
||||
do_searchcount_test 6.3.2 {
|
||||
SELECT c FROM x1 WHERE a=1 OR b=10;
|
||||
} {3 11 search 5}
|
||||
do_searchcount_test 6.3.3 {
|
||||
SELECT rowid FROM x1 WHERE a=1 OR b=10;
|
||||
} {1 3 search 4}
|
||||
|
||||
do_searchcount_test 6.4.1 {
|
||||
SELECT a FROM x1 WHERE b BETWEEN 1 AND 4 OR c BETWEEN 8 AND 12
|
||||
} {1 9 search 6}
|
||||
do_searchcount_test 6.4.2 {
|
||||
SELECT b, c FROM x1 WHERE b BETWEEN 1 AND 4 OR c BETWEEN 8 AND 12
|
||||
} {2 3 10 11 search 5}
|
||||
do_searchcount_test 6.4.3 {
|
||||
SELECT rowid, c FROM x1 WHERE b BETWEEN 1 AND 4 OR c BETWEEN 8 AND 12
|
||||
} {1 3 3 11 search 4}
|
||||
|
||||
do_searchcount_test 6.5.1 {
|
||||
SELECT a FROM x1 WHERE rowid = 2 OR c=11
|
||||
} {5 9 search 3}
|
||||
do_searchcount_test 6.5.2 {
|
||||
SELECT d FROM x1 WHERE rowid = 2 OR c=11
|
||||
} {8 12 search 2}
|
||||
do_searchcount_test 6.5.3 {
|
||||
SELECT d FROM x1 WHERE c=11 OR rowid = 2
|
||||
} {12 8 search 2}
|
||||
do_searchcount_test 6.5.4 {
|
||||
SELECT a FROM x1 WHERE c=11 OR rowid = 2
|
||||
} {9 5 search 3}
|
||||
|
||||
do_searchcount_test 6.6.1 {
|
||||
SELECT rowid FROM x1 WHERE a=1 OR b=6 OR c=11
|
||||
} {1 2 3 search 6}
|
||||
do_searchcount_test 6.6.2 {
|
||||
SELECT c FROM x1 WHERE a=1 OR b=6 OR c=11
|
||||
} {3 7 11 search 7}
|
||||
do_searchcount_test 6.6.3 {
|
||||
SELECT c FROM x1 WHERE c=11 OR a=1 OR b=6
|
||||
} {11 3 7 search 7}
|
||||
do_searchcount_test 6.6.4 {
|
||||
SELECT c FROM x1 WHERE b=6 OR c=11 OR a=1
|
||||
} {7 11 3 search 7}
|
||||
|
||||
finish_test
|
||||
|
Loading…
Reference in New Issue
Block a user