mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-18 10:21:03 +03:00
If a skip-scan is a proper subset of some other scan, then adjust the
cost of the skip-scan upward so that it is more costly than the other scan. Such a cost imbalance can arise under STAT4 because of difficulties in getting an accurate estimate for skip-scans. FossilOrigin-Name: f4b22a2620a5dc48949048c2ecbd226755d4b2c3
This commit is contained in:
15
manifest
15
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Fix\sa\s(probably\sharmless)\sbut\sin\sthe\sCSV\soutput\smode\sof\sthe\scommand-line\nshell.
|
C If\sa\sskip-scan\sis\sa\sproper\ssubset\sof\ssome\sother\sscan,\sthen\sadjust\sthe\ncost\sof\sthe\sskip-scan\supward\sso\sthat\sit\sis\smore\scostly\sthan\sthe\sother\sscan.\nSuch\sa\scost\simbalance\scan\sarise\sunder\sSTAT4\sbecause\sof\sdifficulties\sin\sgetting\nan\saccurate\sestimate\sfor\sskip-scans.
|
||||||
D 2014-10-17T21:35:05.954
|
D 2014-10-21T01:05:09.795
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
|
F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@@ -302,8 +302,8 @@ F src/vtab.c cb0c194303fea276b48d7d4b6d970b5a96bde8de
|
|||||||
F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983
|
F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983
|
||||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||||
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
|
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
|
||||||
F src/where.c 2947912f1f3d6a7766fe087fd532a5d688d745b1
|
F src/where.c 2d1ff51eede0e4dcc87569dc8e3161237295162a
|
||||||
F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c
|
F src/whereInt.h 4b459cdbfc9b01f5f27673a35f9967e4dea917e8
|
||||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||||
F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
|
F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7
|
||||||
@@ -844,6 +844,7 @@ F test/skipscan1.test 7e15e1cc524524e7b2c4595ec85c75501d22f4ff
|
|||||||
F test/skipscan2.test d1d1450952b7275f0b0a3a981f0230532743951a
|
F test/skipscan2.test d1d1450952b7275f0b0a3a981f0230532743951a
|
||||||
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
|
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
|
||||||
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
|
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
|
||||||
|
F test/skipscan6.test 3a891b45d6df266ced861a2ad9d03fca2bc7fcc5
|
||||||
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
||||||
F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
|
F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
|
||||||
F test/sort.test c4400e7533748f6bd7413851ff148645e82b9e2d
|
F test/sort.test c4400e7533748f6bd7413851ff148645e82b9e2d
|
||||||
@@ -1204,7 +1205,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
|||||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||||
P e4ab094f8afce0817f4074e823fabe59fc29ebb4
|
P 19fe4a0a475bd94f491031aea7a183f7c0515cf3
|
||||||
R bacb142e035c538b5014a902fee951f4
|
R 7ae877aeccb485915279368cd2f54415
|
||||||
U drh
|
U drh
|
||||||
Z 99accb7d1ae416e10fed302750dd8f99
|
Z dece11d7f7de853e09f0182395012c8f
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
19fe4a0a475bd94f491031aea7a183f7c0515cf3
|
f4b22a2620a5dc48949048c2ecbd226755d4b2c3
|
||||||
121
src/where.c
121
src/where.c
@@ -2638,7 +2638,7 @@ static int codeAllEqualityTerms(
|
|||||||
pLoop = pLevel->pWLoop;
|
pLoop = pLevel->pWLoop;
|
||||||
assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 );
|
assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 );
|
||||||
nEq = pLoop->u.btree.nEq;
|
nEq = pLoop->u.btree.nEq;
|
||||||
nSkip = pLoop->u.btree.nSkip;
|
nSkip = pLoop->nSkip;
|
||||||
pIdx = pLoop->u.btree.pIndex;
|
pIdx = pLoop->u.btree.pIndex;
|
||||||
assert( pIdx!=0 );
|
assert( pIdx!=0 );
|
||||||
|
|
||||||
@@ -2752,7 +2752,7 @@ static void explainAppendTerm(
|
|||||||
static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){
|
static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){
|
||||||
Index *pIndex = pLoop->u.btree.pIndex;
|
Index *pIndex = pLoop->u.btree.pIndex;
|
||||||
u16 nEq = pLoop->u.btree.nEq;
|
u16 nEq = pLoop->u.btree.nEq;
|
||||||
u16 nSkip = pLoop->u.btree.nSkip;
|
u16 nSkip = pLoop->nSkip;
|
||||||
int i, j;
|
int i, j;
|
||||||
Column *aCol = pTab->aCol;
|
Column *aCol = pTab->aCol;
|
||||||
i16 *aiColumn = pIndex->aiColumn;
|
i16 *aiColumn = pIndex->aiColumn;
|
||||||
@@ -3189,7 +3189,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
|
|
||||||
pIdx = pLoop->u.btree.pIndex;
|
pIdx = pLoop->u.btree.pIndex;
|
||||||
iIdxCur = pLevel->iIdxCur;
|
iIdxCur = pLevel->iIdxCur;
|
||||||
assert( nEq>=pLoop->u.btree.nSkip );
|
assert( nEq>=pLoop->nSkip );
|
||||||
|
|
||||||
/* If this loop satisfies a sort order (pOrderBy) request that
|
/* If this loop satisfies a sort order (pOrderBy) request that
|
||||||
** was passed to this function to implement a "SELECT min(x) ..."
|
** was passed to this function to implement a "SELECT min(x) ..."
|
||||||
@@ -3206,7 +3206,7 @@ static Bitmask codeOneLoopStart(
|
|||||||
&& pWInfo->nOBSat>0
|
&& pWInfo->nOBSat>0
|
||||||
&& (pIdx->nKeyCol>nEq)
|
&& (pIdx->nKeyCol>nEq)
|
||||||
){
|
){
|
||||||
assert( pLoop->u.btree.nSkip==0 );
|
assert( pLoop->nSkip==0 );
|
||||||
bSeekPastNull = 1;
|
bSeekPastNull = 1;
|
||||||
nExtraReg = 1;
|
nExtraReg = 1;
|
||||||
}
|
}
|
||||||
@@ -3827,7 +3827,7 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
|
|||||||
sqlite3_free(z);
|
sqlite3_free(z);
|
||||||
}
|
}
|
||||||
if( p->wsFlags & WHERE_SKIPSCAN ){
|
if( p->wsFlags & WHERE_SKIPSCAN ){
|
||||||
sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->u.btree.nSkip);
|
sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->nSkip);
|
||||||
}else{
|
}else{
|
||||||
sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
|
sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
|
||||||
}
|
}
|
||||||
@@ -3956,12 +3956,15 @@ static int whereLoopCheaperProperSubset(
|
|||||||
const WhereLoop *pY /* Compare against this WhereLoop */
|
const WhereLoop *pY /* Compare against this WhereLoop */
|
||||||
){
|
){
|
||||||
int i, j;
|
int i, j;
|
||||||
if( pX->nLTerm >= pY->nLTerm ) return 0; /* X is not a subset of Y */
|
if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
|
||||||
|
return 0; /* X is not a subset of Y */
|
||||||
|
}
|
||||||
if( pX->rRun >= pY->rRun ){
|
if( pX->rRun >= pY->rRun ){
|
||||||
if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */
|
if( pX->rRun > pY->rRun ) return 0; /* X costs more than Y */
|
||||||
if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */
|
if( pX->nOut > pY->nOut ) return 0; /* X costs more than Y */
|
||||||
}
|
}
|
||||||
for(i=pX->nLTerm-1; i>=0; i--){
|
for(i=pX->nLTerm-1; i>=0; i--){
|
||||||
|
if( pX->aLTerm[i]==0 ) continue;
|
||||||
for(j=pY->nLTerm-1; j>=0; j--){
|
for(j=pY->nLTerm-1; j>=0; j--){
|
||||||
if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
|
if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
|
||||||
}
|
}
|
||||||
@@ -3983,25 +3986,12 @@ static int whereLoopCheaperProperSubset(
|
|||||||
** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
|
** To say "WhereLoop X is a proper subset of Y" means that X uses fewer
|
||||||
** WHERE clause terms than Y and that every WHERE clause term used by X is
|
** WHERE clause terms than Y and that every WHERE clause term used by X is
|
||||||
** also used by Y.
|
** also used by Y.
|
||||||
**
|
|
||||||
** This adjustment is omitted for SKIPSCAN loops. In a SKIPSCAN loop, the
|
|
||||||
** WhereLoop.nLTerm field is not an accurate measure of the number of WHERE
|
|
||||||
** clause terms covered, since some of the first nLTerm entries in aLTerm[]
|
|
||||||
** will be NULL (because they are skipped). That makes it more difficult
|
|
||||||
** to compare the loops. We could add extra code to do the comparison, and
|
|
||||||
** perhaps we will someday. But SKIPSCAN is sufficiently uncommon, and this
|
|
||||||
** adjustment is sufficient minor, that it is very difficult to construct
|
|
||||||
** a test case where the extra code would improve the query plan. Better
|
|
||||||
** to avoid the added complexity and just omit cost adjustments to SKIPSCAN
|
|
||||||
** loops.
|
|
||||||
*/
|
*/
|
||||||
static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
|
static void whereLoopAdjustCost(const WhereLoop *p, WhereLoop *pTemplate){
|
||||||
if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
|
if( (pTemplate->wsFlags & WHERE_INDEXED)==0 ) return;
|
||||||
if( (pTemplate->wsFlags & WHERE_SKIPSCAN)!=0 ) return;
|
|
||||||
for(; p; p=p->pNextLoop){
|
for(; p; p=p->pNextLoop){
|
||||||
if( p->iTab!=pTemplate->iTab ) continue;
|
if( p->iTab!=pTemplate->iTab ) continue;
|
||||||
if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
|
if( (p->wsFlags & WHERE_INDEXED)==0 ) continue;
|
||||||
if( (p->wsFlags & WHERE_SKIPSCAN)!=0 ) continue;
|
|
||||||
if( whereLoopCheaperProperSubset(p, pTemplate) ){
|
if( whereLoopCheaperProperSubset(p, pTemplate) ){
|
||||||
/* Adjust pTemplate cost downward so that it is cheaper than its
|
/* Adjust pTemplate cost downward so that it is cheaper than its
|
||||||
** subset p */
|
** subset p */
|
||||||
@@ -4295,7 +4285,7 @@ static int whereLoopAddBtreeIndex(
|
|||||||
Bitmask saved_prereq; /* Original value of pNew->prereq */
|
Bitmask saved_prereq; /* Original value of pNew->prereq */
|
||||||
u16 saved_nLTerm; /* Original value of pNew->nLTerm */
|
u16 saved_nLTerm; /* Original value of pNew->nLTerm */
|
||||||
u16 saved_nEq; /* Original value of pNew->u.btree.nEq */
|
u16 saved_nEq; /* Original value of pNew->u.btree.nEq */
|
||||||
u16 saved_nSkip; /* Original value of pNew->u.btree.nSkip */
|
u16 saved_nSkip; /* Original value of pNew->nSkip */
|
||||||
u32 saved_wsFlags; /* Original value of pNew->wsFlags */
|
u32 saved_wsFlags; /* Original value of pNew->wsFlags */
|
||||||
LogEst saved_nOut; /* Original value of pNew->nOut */
|
LogEst saved_nOut; /* Original value of pNew->nOut */
|
||||||
int iCol; /* Index of the column in the table */
|
int iCol; /* Index of the column in the table */
|
||||||
@@ -4324,7 +4314,7 @@ static int whereLoopAddBtreeIndex(
|
|||||||
pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol,
|
pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol,
|
||||||
opMask, pProbe);
|
opMask, pProbe);
|
||||||
saved_nEq = pNew->u.btree.nEq;
|
saved_nEq = pNew->u.btree.nEq;
|
||||||
saved_nSkip = pNew->u.btree.nSkip;
|
saved_nSkip = pNew->nSkip;
|
||||||
saved_nLTerm = pNew->nLTerm;
|
saved_nLTerm = pNew->nLTerm;
|
||||||
saved_wsFlags = pNew->wsFlags;
|
saved_wsFlags = pNew->wsFlags;
|
||||||
saved_prereq = pNew->prereq;
|
saved_prereq = pNew->prereq;
|
||||||
@@ -4332,44 +4322,6 @@ static int whereLoopAddBtreeIndex(
|
|||||||
pNew->rSetup = 0;
|
pNew->rSetup = 0;
|
||||||
rSize = pProbe->aiRowLogEst[0];
|
rSize = pProbe->aiRowLogEst[0];
|
||||||
rLogSize = estLog(rSize);
|
rLogSize = estLog(rSize);
|
||||||
|
|
||||||
/* Consider using a skip-scan if there are no WHERE clause constraints
|
|
||||||
** available for the left-most terms of the index, and if the average
|
|
||||||
** number of repeats in the left-most terms is at least 18.
|
|
||||||
**
|
|
||||||
** The magic number 18 is selected on the basis that scanning 17 rows
|
|
||||||
** is almost always quicker than an index seek (even though if the index
|
|
||||||
** contains fewer than 2^17 rows we assume otherwise in other parts of
|
|
||||||
** the code). And, even if it is not, it should not be too much slower.
|
|
||||||
** On the other hand, the extra seeks could end up being significantly
|
|
||||||
** more expensive. */
|
|
||||||
assert( 42==sqlite3LogEst(18) );
|
|
||||||
if( saved_nEq==saved_nSkip
|
|
||||||
&& saved_nEq+1<pProbe->nKeyCol
|
|
||||||
&& pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
|
|
||||||
&& (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
|
|
||||||
){
|
|
||||||
LogEst nIter;
|
|
||||||
pNew->u.btree.nEq++;
|
|
||||||
pNew->u.btree.nSkip++;
|
|
||||||
pNew->aLTerm[pNew->nLTerm++] = 0;
|
|
||||||
pNew->wsFlags |= WHERE_SKIPSCAN;
|
|
||||||
nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1];
|
|
||||||
if( pTerm ){
|
|
||||||
/* TUNING: When estimating skip-scan for a term that is also indexable,
|
|
||||||
** multiply the cost of the skip-scan by 2.0, to make it a little less
|
|
||||||
** desirable than the regular index lookup. */
|
|
||||||
nIter += 10; assert( 10==sqlite3LogEst(2) );
|
|
||||||
}
|
|
||||||
pNew->nOut -= nIter;
|
|
||||||
/* TUNING: Because uncertainties in the estimates for skip-scan queries,
|
|
||||||
** add a 1.375 fudge factor to make skip-scan slightly less likely. */
|
|
||||||
nIter += 5;
|
|
||||||
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul);
|
|
||||||
pNew->nOut = saved_nOut;
|
|
||||||
pNew->u.btree.nEq = saved_nEq;
|
|
||||||
pNew->u.btree.nSkip = saved_nSkip;
|
|
||||||
}
|
|
||||||
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
|
for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
|
||||||
u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */
|
u16 eOp = pTerm->eOperator; /* Shorthand for pTerm->eOperator */
|
||||||
LogEst rCostIdx;
|
LogEst rCostIdx;
|
||||||
@@ -4532,10 +4484,50 @@ static int whereLoopAddBtreeIndex(
|
|||||||
}
|
}
|
||||||
pNew->prereq = saved_prereq;
|
pNew->prereq = saved_prereq;
|
||||||
pNew->u.btree.nEq = saved_nEq;
|
pNew->u.btree.nEq = saved_nEq;
|
||||||
pNew->u.btree.nSkip = saved_nSkip;
|
pNew->nSkip = saved_nSkip;
|
||||||
pNew->wsFlags = saved_wsFlags;
|
pNew->wsFlags = saved_wsFlags;
|
||||||
pNew->nOut = saved_nOut;
|
pNew->nOut = saved_nOut;
|
||||||
pNew->nLTerm = saved_nLTerm;
|
pNew->nLTerm = saved_nLTerm;
|
||||||
|
|
||||||
|
/* Consider using a skip-scan if there are no WHERE clause constraints
|
||||||
|
** available for the left-most terms of the index, and if the average
|
||||||
|
** number of repeats in the left-most terms is at least 18.
|
||||||
|
**
|
||||||
|
** The magic number 18 is selected on the basis that scanning 17 rows
|
||||||
|
** is almost always quicker than an index seek (even though if the index
|
||||||
|
** contains fewer than 2^17 rows we assume otherwise in other parts of
|
||||||
|
** the code). And, even if it is not, it should not be too much slower.
|
||||||
|
** On the other hand, the extra seeks could end up being significantly
|
||||||
|
** more expensive. */
|
||||||
|
assert( 42==sqlite3LogEst(18) );
|
||||||
|
if( saved_nEq==saved_nSkip
|
||||||
|
&& saved_nEq+1<pProbe->nKeyCol
|
||||||
|
&& pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
|
||||||
|
&& (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
|
||||||
|
){
|
||||||
|
LogEst nIter;
|
||||||
|
pNew->u.btree.nEq++;
|
||||||
|
pNew->nSkip++;
|
||||||
|
pNew->aLTerm[pNew->nLTerm++] = 0;
|
||||||
|
pNew->wsFlags |= WHERE_SKIPSCAN;
|
||||||
|
nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1];
|
||||||
|
if( pTerm ){
|
||||||
|
/* TUNING: When estimating skip-scan for a term that is also indexable,
|
||||||
|
** multiply the cost of the skip-scan by 2.0, to make it a little less
|
||||||
|
** desirable than the regular index lookup. */
|
||||||
|
nIter += 10; assert( 10==sqlite3LogEst(2) );
|
||||||
|
}
|
||||||
|
pNew->nOut -= nIter;
|
||||||
|
/* TUNING: Because uncertainties in the estimates for skip-scan queries,
|
||||||
|
** add a 1.375 fudge factor to make skip-scan slightly less likely. */
|
||||||
|
nIter += 5;
|
||||||
|
whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul);
|
||||||
|
pNew->nOut = saved_nOut;
|
||||||
|
pNew->u.btree.nEq = saved_nEq;
|
||||||
|
pNew->nSkip = saved_nSkip;
|
||||||
|
pNew->wsFlags = saved_wsFlags;
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4714,7 +4706,7 @@ static int whereLoopAddBtree(
|
|||||||
if( pTerm->prereqRight & pNew->maskSelf ) continue;
|
if( pTerm->prereqRight & pNew->maskSelf ) continue;
|
||||||
if( termCanDriveIndex(pTerm, pSrc, 0) ){
|
if( termCanDriveIndex(pTerm, pSrc, 0) ){
|
||||||
pNew->u.btree.nEq = 1;
|
pNew->u.btree.nEq = 1;
|
||||||
pNew->u.btree.nSkip = 0;
|
pNew->nSkip = 0;
|
||||||
pNew->u.btree.pIndex = 0;
|
pNew->u.btree.pIndex = 0;
|
||||||
pNew->nLTerm = 1;
|
pNew->nLTerm = 1;
|
||||||
pNew->aLTerm[0] = pTerm;
|
pNew->aLTerm[0] = pTerm;
|
||||||
@@ -4755,7 +4747,7 @@ static int whereLoopAddBtree(
|
|||||||
}
|
}
|
||||||
rSize = pProbe->aiRowLogEst[0];
|
rSize = pProbe->aiRowLogEst[0];
|
||||||
pNew->u.btree.nEq = 0;
|
pNew->u.btree.nEq = 0;
|
||||||
pNew->u.btree.nSkip = 0;
|
pNew->nSkip = 0;
|
||||||
pNew->nLTerm = 0;
|
pNew->nLTerm = 0;
|
||||||
pNew->iSortIdx = 0;
|
pNew->iSortIdx = 0;
|
||||||
pNew->rSetup = 0;
|
pNew->rSetup = 0;
|
||||||
@@ -5305,7 +5297,7 @@ static i8 wherePathSatisfiesOrderBy(
|
|||||||
|
|
||||||
/* Skip over == and IS NULL terms */
|
/* Skip over == and IS NULL terms */
|
||||||
if( j<pLoop->u.btree.nEq
|
if( j<pLoop->u.btree.nEq
|
||||||
&& pLoop->u.btree.nSkip==0
|
&& pLoop->nSkip==0
|
||||||
&& ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0
|
&& ((i = pLoop->aLTerm[j]->eOperator) & (WO_EQ|WO_ISNULL))!=0
|
||||||
){
|
){
|
||||||
if( i & WO_ISNULL ){
|
if( i & WO_ISNULL ){
|
||||||
@@ -5878,7 +5870,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
|||||||
pWC = &pWInfo->sWC;
|
pWC = &pWInfo->sWC;
|
||||||
pLoop = pBuilder->pNew;
|
pLoop = pBuilder->pNew;
|
||||||
pLoop->wsFlags = 0;
|
pLoop->wsFlags = 0;
|
||||||
pLoop->u.btree.nSkip = 0;
|
pLoop->nSkip = 0;
|
||||||
pTerm = findTerm(pWC, iCur, -1, 0, WO_EQ, 0);
|
pTerm = findTerm(pWC, iCur, -1, 0, WO_EQ, 0);
|
||||||
if( pTerm ){
|
if( pTerm ){
|
||||||
pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW;
|
pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW;
|
||||||
@@ -5890,7 +5882,6 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
|||||||
}else{
|
}else{
|
||||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||||
assert( pLoop->aLTermSpace==pLoop->aLTerm );
|
assert( pLoop->aLTermSpace==pLoop->aLTerm );
|
||||||
assert( ArraySize(pLoop->aLTermSpace)==4 );
|
|
||||||
if( !IsUniqueIndex(pIdx)
|
if( !IsUniqueIndex(pIdx)
|
||||||
|| pIdx->pPartIdxWhere!=0
|
|| pIdx->pPartIdxWhere!=0
|
||||||
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
|
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
|
||||||
|
|||||||
@@ -115,7 +115,6 @@ struct WhereLoop {
|
|||||||
union {
|
union {
|
||||||
struct { /* Information for internal btree tables */
|
struct { /* Information for internal btree tables */
|
||||||
u16 nEq; /* Number of equality constraints */
|
u16 nEq; /* Number of equality constraints */
|
||||||
u16 nSkip; /* Number of initial index columns to skip */
|
|
||||||
Index *pIndex; /* Index used, or NULL */
|
Index *pIndex; /* Index used, or NULL */
|
||||||
} btree;
|
} btree;
|
||||||
struct { /* Information for virtual tables */
|
struct { /* Information for virtual tables */
|
||||||
@@ -128,12 +127,13 @@ struct WhereLoop {
|
|||||||
} u;
|
} u;
|
||||||
u32 wsFlags; /* WHERE_* flags describing the plan */
|
u32 wsFlags; /* WHERE_* flags describing the plan */
|
||||||
u16 nLTerm; /* Number of entries in aLTerm[] */
|
u16 nLTerm; /* Number of entries in aLTerm[] */
|
||||||
|
u16 nSkip; /* Number of NULL aLTerm[] entries */
|
||||||
/**** whereLoopXfer() copies fields above ***********************/
|
/**** whereLoopXfer() copies fields above ***********************/
|
||||||
# define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot)
|
# define WHERE_LOOP_XFER_SZ offsetof(WhereLoop,nLSlot)
|
||||||
u16 nLSlot; /* Number of slots allocated for aLTerm[] */
|
u16 nLSlot; /* Number of slots allocated for aLTerm[] */
|
||||||
WhereTerm **aLTerm; /* WhereTerms used */
|
WhereTerm **aLTerm; /* WhereTerms used */
|
||||||
WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
|
WhereLoop *pNextLoop; /* Next WhereLoop object in the WhereClause */
|
||||||
WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */
|
WhereTerm *aLTermSpace[3]; /* Initial aLTerm[] space */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This object holds the prerequisites and the cost of running a
|
/* This object holds the prerequisites and the cost of running a
|
||||||
|
|||||||
145
test/skipscan6.test
Normal file
145
test/skipscan6.test
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# 2014-10-21
|
||||||
|
#
|
||||||
|
# The author disclaims copyright to this source code. In place of
|
||||||
|
# a legal notice, here is a blessing:
|
||||||
|
#
|
||||||
|
# May you do good and not evil.
|
||||||
|
# May you find forgiveness for yourself and forgive others.
|
||||||
|
# May you share freely, never taking more than you give.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
#
|
||||||
|
# This file implements tests of the "skip-scan" query strategy. In
|
||||||
|
# particular, this file verifies that use of all columns of an index
|
||||||
|
# is always preferred over the use of a skip-scan on some columns of
|
||||||
|
# the same index. Because of difficulties in scoring a skip-scan,
|
||||||
|
# the skip-scan can sometimes come out with a lower raw score when
|
||||||
|
# using STAT4. But the query planner should detect this and use the
|
||||||
|
# full index rather than the skip-scan.
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
set testprefix skipscan6
|
||||||
|
|
||||||
|
ifcapable !stat4 {
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test 1.1 {
|
||||||
|
CREATE TABLE t1(
|
||||||
|
aa int,
|
||||||
|
bb int,
|
||||||
|
cc int,
|
||||||
|
dd int,
|
||||||
|
ee int
|
||||||
|
);
|
||||||
|
CREATE INDEX ix on t1(aa, bb, cc, dd DESC);
|
||||||
|
ANALYZE sqlite_master;
|
||||||
|
INSERT INTO sqlite_stat1 VALUES('t1','ix','2695116 1347558 264 18 2');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 196859 196859 32 1','0 15043 15043 92468 92499','0 19 286 81846 92499',X'0609010804031552977BD725BD28');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 14687 161 1 1','0 289067 299306 299457 299457','0 199 6772 273984 299457',X'060902020403013406314D67456415B819');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 19313 19308 22 1','0 325815 325815 343725 343746','0 261 9545 315009 343746',X'060902080403018A49B0A3AD1ED931');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 25047 9051 15 1','0 350443 350443 356590 356604','0 266 9795 325519 356604',X'06090208040301914C2DD2E91F93CF');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 42327 9906 7 1','0 376381 376381 380291 380297','0 268 10100 344232 380297',X'06090208040301934BF672511F7ED3');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 24513 2237 1 1','0 455150 467779 470015 470015','0 286 10880 425401 470015',X'06090202040301A703464A28F2611EF1EE');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 18730 18724 15 1','0 479663 479663 498271 498285','0 287 10998 450793 498285',X'06090208040301A8494AF3A41EC50C');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 119603 47125 1 1','0 572425 572425 598915 598915','0 404 14230 546497 598915',X'06090208040302474FD1929A03194F');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 1454 1454 1 1','0 898346 898346 898373 898373','0 952 31165 827562 898373',X'06090208040304FD53F6A2A2097F64');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 57138 7069 1 1','0 1122389 1122389 1129457 1129457','0 1967 46801 1045943 1129457',X'06090208040309884BC4C52F1F6EB7');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 285 11 1 1','0 1197683 1197824 1197831 1197831','0 2033 50990 1112280 1197831',X'06090202040309D80346503FE2A9038E4F');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 25365 9773 1 1','0 1301013 1301013 1310785 1310785','0 2561 58806 1217877 1310785',X'0609020804030C5F4C8F88AB0AF2A2');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 45180 7222 1 1','0 1326378 1326378 1333599 1333599','0 2562 59921 1240187 1333599',X'0609020804030C604CAB75490B0351');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 8537 41 1 1','0 1496959 1497288 1497289 1497289','0 3050 68246 1394126 1497289',X'0609020204030EA0057F527459B0257C4B');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 26139 26131 17 1','0 1507977 1507977 1520578 1520594','0 3074 69188 1416111 1520594',X'0609020804030EB95169453423D4EA');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 102894 29678 1 1','0 1537421 1550467 1564894 1564894','0 3109 69669 1459820 1564894',X'0609020204030EE3183652A6ED3006EBCB');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 319 3 1 1','0 1796728 1796746 1796747 1796747','0 3650 86468 1682243 1796747',X'0609020204031163033550D0C41018C28D');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 127 127 1 1','0 2096194 2096194 2096205 2096205','0 5145 106437 1951535 2096205',X'060902080403180F53BB1AF727EE50');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 66574 5252 1 1','0 2230524 2265961 2271212 2271212','0 5899 114976 2085829 2271212',X'0609020204031B8A05195009976D223B90');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 19440 19440 1 1','0 2391680 2391680 2395663 2395663','0 6718 123714 2184781 2395663',X'0609020804031F7452E00A7B07431A');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 18321 2177 1 1','0 2522928 2523231 2525407 2525407','0 7838 139084 2299958 2525407',X'06090201040324A7475231103B1AA7B8');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 22384 1361 1 1','0 2541249 2544834 2546194 2546194','0 7839 139428 2308416 2546194',X'06090202040324A8011652323D4B1AA9EB');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','2677151 18699 855 1 1','0 2563633 2578178 2579032 2579032','0 7840 139947 2321671 2579032',X'06090202040324A9077452323D7D1052C5');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','ix','17965 1579 1579 1 1','2677151 2690666 2690666 2692244 2692244','1 9870 153959 2418294 2692244',X'060102080403021B8A4FE1AB84032B35');
|
||||||
|
ANALYZE sqlite_master;
|
||||||
|
} {}
|
||||||
|
do_execsql_test 1.2 {
|
||||||
|
EXPLAIN QUERY PLAN
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM t1
|
||||||
|
WHERE bb=21
|
||||||
|
AND aa=1
|
||||||
|
AND dd BETWEEN 1413833728 and 1413837331;
|
||||||
|
} {/INDEX ix .aa=. AND bb=../}
|
||||||
|
|
||||||
|
do_execsql_test 2.1 {
|
||||||
|
DROP INDEX ix;
|
||||||
|
CREATE INDEX good on t1(bb, aa, dd DESC);
|
||||||
|
CREATE INDEX bad on t1(aa, bb, cc, dd DESC);
|
||||||
|
DELETE FROM sqlite_stat1;
|
||||||
|
DELETE FROM sqlite_stat4;
|
||||||
|
INSERT INTO sqlite_stat1 VALUES('t1','good','2695116 299 264 2');
|
||||||
|
INSERT INTO sqlite_stat1 VALUES('t1','bad','2695116 1347558 264 18 2');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','197030 196859 32 1','15086 15086 92511 92536','19 25 81644 92536',X'05010904031552977BD725BD22');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','14972 14687 1 1','289878 289878 299457 299457','199 244 267460 299457',X'050209040301344F7E569402C419');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','19600 19313 22 1','327127 327127 346222 346243','261 319 306884 346243',X'0502090403018A49503BC01EC577');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','25666 25047 15 1','352087 352087 372692 372706','266 327 325601 372706',X'050209040301914C2DD2E91F93CF');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','42392 42327 26 1','378657 378657 382547 382572','268 331 333529 382572',X'05020904030193533B2FE326ED48');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','24619 24513 11 1','457872 457872 461748 461758','286 358 399322 461758',X'050209040301A752B1557825EA7C');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','18969 18730 15 1','482491 482491 501105 501119','287 360 433605 501119',X'050209040301A8494AF3A41EC50C');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','119710 119603 1 1','576500 576500 598915 598915','404 505 519877 598915',X'05020904030247539A7A7912F617');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','11955 11946 1 1','889796 889796 898373 898373','938 1123 794694 898373',X'050209040304EF4DF9C4150BBB28');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','57197 57138 24 1','1129865 1129865 1151492 1151515','1967 2273 1027048 1151515',X'05020904030988533510BC26E20A');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','3609 3543 1 1','1196265 1196265 1197831 1197831','2002 2313 1070108 1197831',X'050209040309B050E95CD718D94D');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','25391 25365 13 1','1309378 1309378 1315567 1315579','2561 2936 1178358 1315579',X'05020904030C5F53DF9E13283570');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','45232 45180 17 1','1334769 1334769 1337946 1337962','2562 2938 1198998 1337962',X'05020904030C60541CACEE28BCAC');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','5496 5493 1 1','1495882 1495882 1497289 1497289','3043 3479 1348695 1497289',X'05020904030E99515C62AD0F0B34');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','26348 26139 17 1','1517381 1517381 1529990 1530006','3074 3519 1378320 1530006',X'05020904030EB95169453423D4EA');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','102927 102894 10 1','1547088 1547088 1649950 1649959','3109 3559 1494260 1649959',X'05020904030EE34D309F671FFA47');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','3602 3576 1 1','1793873 1793873 1796747 1796747','3601 4128 1630783 1796747',X'050209040311294FE88B432219B9');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','154 154 1 1','2096059 2096059 2096205 2096205','5037 5779 1893039 2096205',X'050209040317994EFF05A016DCED');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','68153 66574 60 1','2244039 2244039 2268892 2268951','5899 6749 2027553 2268951',X'05020904031B8A532DBC5A26D2BA');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','321 321 1 1','2395618 2395618 2395663 2395663','6609 7528 2118435 2395663',X'05020904031EFA54078EEE1E2D65');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','19449 19440 22 1','2407769 2407769 2426049 2426070','6718 7651 2146904 2426070',X'05020904031F7450E6118C2336BD');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','18383 18321 56 1','2539949 2539949 2551080 2551135','7838 8897 2245459 2551135',X'050209040324A752EA2E1E2642B2');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','22479 22384 60 1','2558332 2558332 2565233 2565292','7839 8899 2251202 2565292',X'050209040324A853926538279A5F');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','good','18771 18699 63 1','2580811 2580811 2596914 2596976','7840 8901 2263572 2596976',X'050209040324A9526C1DE9256E72');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 196859 196859 32 1','0 15043 15043 92468 92499','0 19 286 81846 92499',X'0609010804031552977BD725BD28');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 14687 161 1 1','0 289067 299306 299457 299457','0 199 6772 273984 299457',X'060902020403013406314D67456415B819');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 19313 19308 22 1','0 325815 325815 343725 343746','0 261 9545 315009 343746',X'060902080403018A49B0A3AD1ED931');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 25047 9051 15 1','0 350443 350443 356590 356604','0 266 9795 325519 356604',X'06090208040301914C2DD2E91F93CF');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 42327 9906 7 1','0 376381 376381 380291 380297','0 268 10100 344232 380297',X'06090208040301934BF672511F7ED3');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 24513 2237 1 1','0 455150 467779 470015 470015','0 286 10880 425401 470015',X'06090202040301A703464A28F2611EF1EE');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 18730 18724 15 1','0 479663 479663 498271 498285','0 287 10998 450793 498285',X'06090208040301A8494AF3A41EC50C');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 119603 47125 1 1','0 572425 572425 598915 598915','0 404 14230 546497 598915',X'06090208040302474FD1929A03194F');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 1454 1454 1 1','0 898346 898346 898373 898373','0 952 31165 827562 898373',X'06090208040304FD53F6A2A2097F64');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 57138 7069 1 1','0 1122389 1122389 1129457 1129457','0 1967 46801 1045943 1129457',X'06090208040309884BC4C52F1F6EB7');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 285 11 1 1','0 1197683 1197824 1197831 1197831','0 2033 50990 1112280 1197831',X'06090202040309D80346503FE2A9038E4F');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 25365 9773 1 1','0 1301013 1301013 1310785 1310785','0 2561 58806 1217877 1310785',X'0609020804030C5F4C8F88AB0AF2A2');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 45180 7222 1 1','0 1326378 1326378 1333599 1333599','0 2562 59921 1240187 1333599',X'0609020804030C604CAB75490B0351');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 8537 41 1 1','0 1496959 1497288 1497289 1497289','0 3050 68246 1394126 1497289',X'0609020204030EA0057F527459B0257C4B');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 26139 26131 17 1','0 1507977 1507977 1520578 1520594','0 3074 69188 1416111 1520594',X'0609020804030EB95169453423D4EA');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 102894 29678 1 1','0 1537421 1550467 1564894 1564894','0 3109 69669 1459820 1564894',X'0609020204030EE3183652A6ED3006EBCB');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 319 3 1 1','0 1796728 1796746 1796747 1796747','0 3650 86468 1682243 1796747',X'0609020204031163033550D0C41018C28D');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 127 127 1 1','0 2096194 2096194 2096205 2096205','0 5145 106437 1951535 2096205',X'060902080403180F53BB1AF727EE50');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 66574 5252 1 1','0 2230524 2265961 2271212 2271212','0 5899 114976 2085829 2271212',X'0609020204031B8A05195009976D223B90');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 19440 19440 1 1','0 2391680 2391680 2395663 2395663','0 6718 123714 2184781 2395663',X'0609020804031F7452E00A7B07431A');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 18321 2177 1 1','0 2522928 2523231 2525407 2525407','0 7838 139084 2299958 2525407',X'06090201040324A7475231103B1AA7B8');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 22384 1361 1 1','0 2541249 2544834 2546194 2546194','0 7839 139428 2308416 2546194',X'06090202040324A8011652323D4B1AA9EB');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','2677151 18699 855 1 1','0 2563633 2578178 2579032 2579032','0 7840 139947 2321671 2579032',X'06090202040324A9077452323D7D1052C5');
|
||||||
|
INSERT INTO sqlite_stat4 VALUES('t1','bad','17965 1579 1579 1 1','2677151 2690666 2690666 2692244 2692244','1 9870 153959 2418294 2692244',X'060102080403021B8A4FE1AB84032B35');
|
||||||
|
ANALYZE sqlite_master;
|
||||||
|
} {}
|
||||||
|
do_execsql_test 2.2 {
|
||||||
|
EXPLAIN QUERY PLAN
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM t1
|
||||||
|
WHERE bb=21
|
||||||
|
AND aa=1
|
||||||
|
AND dd BETWEEN 1413833728 and 1413837331;
|
||||||
|
} {/INDEX good .bb=. AND aa=. AND dd>. AND dd<../}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
finish_test
|
||||||
Reference in New Issue
Block a user