Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f7d4578313 | |||
| 4e62a13216 | |||
| 268df2d77f | |||
| 2c809de2bd | |||
| b80ffe626c | |||
| fc0cb3a0b8 | |||
| 0cf8896ec8 |
@@ -1,5 +1,5 @@
|
||||
C Defer\sopening\sand\swriting\sstatement\sjournals\suntil\sthe\ssize\sreaches\sa\nthreshold\s(currently\s64KiB).
|
||||
D 2016-03-04T14:43:44.681
|
||||
C Simplify\sthe\scomputation\sof\sIndex.aAvgEq.
|
||||
D 2016-03-04T19:55:02.239
|
||||
F Makefile.in ead489fe5d3313b8a2a8d5f3710173a4b50dd2e0
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc d68db8ddac21ea2576ea5b446f12cf9ebe897a03
|
||||
@@ -286,7 +286,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 1bb0709b3048e24217b80ec6bd78a3e99a47c01b
|
||||
F src/analyze.c ab57b6763dd4c6170a20673d14882c033affd188
|
||||
F src/analyze.c a89554ee91a8b17b8a745770ddcb4e85a1e27a69
|
||||
F src/attach.c a3724c64de1099d85e30751213d285752aed9505
|
||||
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
F src/backup.c f60f0aa55d25d853ffde53d0b0370a7bb7ee41ce
|
||||
@@ -354,7 +354,7 @@ F src/shell.c 5e0ab1e708dc294330ccd8230536e1801f60822e
|
||||
F src/sqlite.h.in 57d2a02b14c9ec4f7cb294153eaf62294dc5aa68
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d
|
||||
F src/sqliteInt.h 8a4810fa90b17eb08acab43649b877e894ea1e98
|
||||
F src/sqliteInt.h 7d1257c165974c64d4715d80ee1122aba4578b4e
|
||||
F src/sqliteLimit.h 7b28cf72cbd52f178bfc97ea266445e351f2cd24
|
||||
F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
|
||||
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
|
||||
@@ -429,7 +429,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 10deb6b43887662691e5f53d10b3c171c401169b
|
||||
F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c
|
||||
F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
|
||||
F src/where.c 56948ada5aacc3bf2628db3776986e8bf4085383
|
||||
F src/where.c 2b61974a8442f2c7afb3905322b56d3d618d2804
|
||||
F src/whereInt.h 93297d56edd137b7ea004490690fb6e2ce028a34
|
||||
F src/wherecode.c 3ca820435c5b597bb50e63ed11e938786fe5c23e
|
||||
F src/whereexpr.c fb87944b1254234e5bba671aaf6dee476241506a
|
||||
@@ -1032,7 +1032,7 @@ F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
F test/shrink.test 1b4330b1fd9e818c04726d45cb28db73087535ce
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
F test/skipscan1.test d37a75b4be4eb9dedeb69b4f38b1d0a74b5021d7
|
||||
F test/skipscan2.test d1d1450952b7275f0b0a3a981f0230532743951a
|
||||
F test/skipscan2.test 4cf572db43ca6b2f3b8162295e984c3555e4abeb
|
||||
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
|
||||
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
|
||||
F test/skipscan6.test 5866039d03a56f5bd0b3d172a012074a1d90a15b
|
||||
@@ -1453,8 +1453,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 2682e8e413fadbca0673f242769af17bfd291559 5b2fe5219ab9ad15969e3374894a75979b65cb3c
|
||||
R bcfeac6deb0b24b3190e8b427e406c58
|
||||
T +closed 5b2fe5219ab9ad15969e3374894a75979b65cb3c
|
||||
P 5294c977d9b15a4f29028782ef253329bd739fc0
|
||||
R 0d9736ab8ee345d5b31279fe6ba1cf6e
|
||||
U drh
|
||||
Z 04f483c25715ded0ed1694d083bfc434
|
||||
Z 7c24b575cc7f48aed8f15dbed80ebac8
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
cb9302cca423de41305719a49208daa392ec09da
|
||||
c448873006cda294cdaf6b61e75a07f121ba34ea
|
||||
+77
-51
@@ -267,6 +267,7 @@ typedef struct Stat4Sample Stat4Sample;
|
||||
struct Stat4Sample {
|
||||
tRowcnt *anEq; /* sqlite_stat4.nEq */
|
||||
tRowcnt *anDLt; /* sqlite_stat4.nDLt */
|
||||
tRowcnt *amxEq; /* Maximum length run of equal values */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
tRowcnt *anLt; /* sqlite_stat4.nLt */
|
||||
union {
|
||||
@@ -418,6 +419,7 @@ static void statInit(
|
||||
/* Allocate the space required for the Stat4Accum object */
|
||||
n = sizeof(*p)
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.amxEq */
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
+ sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */
|
||||
@@ -436,18 +438,19 @@ static void statInit(
|
||||
p->nRow = 0;
|
||||
p->nCol = nCol;
|
||||
p->nKeyCol = nKeyCol;
|
||||
p->current.anDLt = (tRowcnt*)&p[1];
|
||||
p->current.anEq = &p->current.anDLt[nColUp];
|
||||
p->current.anEq = (tRowcnt*)&p[1];
|
||||
p->current.amxEq = &p->current.anEq[nColUp];
|
||||
p->current.anDLt = &p->current.amxEq[nColUp];
|
||||
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
{
|
||||
u8 *pSpace; /* Allocated space not yet assigned */
|
||||
int i; /* Used to iterate through p->aSample[] */
|
||||
int i; /* Loop counter */
|
||||
|
||||
p->iGet = -1;
|
||||
p->mxSample = mxSample;
|
||||
p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
|
||||
p->current.anLt = &p->current.anEq[nColUp];
|
||||
p->current.anLt = &p->current.anDLt[nColUp];
|
||||
p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
|
||||
|
||||
/* Set up the Stat4Accum.a[] and aBest[] arrays */
|
||||
@@ -721,7 +724,10 @@ static void statPush(
|
||||
|
||||
if( p->nRow==0 ){
|
||||
/* This is the first call to this function. Do initialization. */
|
||||
for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
|
||||
for(i=0; i<p->nCol; i++){
|
||||
p->current.anEq[i] = 1;
|
||||
p->current.amxEq[i] = 1;
|
||||
}
|
||||
}else{
|
||||
/* Second and subsequent calls get processed here */
|
||||
samplePushPrevious(p, iChng);
|
||||
@@ -729,6 +735,7 @@ static void statPush(
|
||||
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
|
||||
** to the current row of the index. */
|
||||
for(i=0; i<iChng; i++){
|
||||
if( p->current.amxEq[i]==p->current.anEq[i] ) p->current.amxEq[i]++;
|
||||
p->current.anEq[i]++;
|
||||
}
|
||||
for(i=iChng; i<p->nCol; i++){
|
||||
@@ -821,31 +828,53 @@ static void statGet(
|
||||
assert( argc==1 );
|
||||
#endif
|
||||
{
|
||||
/* Return the value to store in the "stat" column of the sqlite_stat1
|
||||
/* Return a value for the "stat" column of the sqlite_stat1
|
||||
** table for this index.
|
||||
**
|
||||
** The value is a string composed of a list of integers describing
|
||||
** the index. The first integer in the list is the total number of
|
||||
** entries in the index. There is one additional integer in the list
|
||||
** for each indexed column. This additional integer is an estimate of
|
||||
** the number of rows matched by a stabbing query on the index using
|
||||
** a key with the corresponding number of fields. In other words,
|
||||
** if the index is on columns (a,b) and the sqlite_stat1 value is
|
||||
** "100 10 2", then SQLite estimates that:
|
||||
** the index. The first integer is the (estimated) total number
|
||||
** entries in the index. There is one additional integer for each
|
||||
** column in the index. The first added integer is an estimate of
|
||||
** the number of rows that match a single key in the first column of
|
||||
** the index. The second added integer is an estimate on of the number
|
||||
** of rows that match a single key consisting of the first two columns
|
||||
** of the index. And so forth.
|
||||
**
|
||||
** * the index contains 100 rows,
|
||||
** * "WHERE a=?" matches 10 rows, and
|
||||
** * "WHERE a=? AND b=?" matches 2 rows.
|
||||
** For example, for an index on columns (a,b), if the sqlite_stat1.stat
|
||||
** values is "100 10 2", that means there are about 100 rows in the
|
||||
** index, and that a query against a=$key1 will match about 10 rows
|
||||
** and a query against "a=$key1 AND b=$key2" will match about 2 rows.
|
||||
**
|
||||
** If D is the count of distinct values and K is the total number of
|
||||
** rows, then each estimate is computed as:
|
||||
** Let V be the average number of rows that match a key, and let M
|
||||
** be the most number of rows that match the key for any possible value
|
||||
** of that key. The estimate is computed as:
|
||||
**
|
||||
** I = (K+D-1)/D
|
||||
** E = (2*V + M)/3
|
||||
**
|
||||
** Consider two indexes. Index X has with 100 values of exactly 0 and
|
||||
** 100 singleton values between 1 and 100. Index Y has 200 values
|
||||
** evenly distributed between 1 and 20. If only the average (V) is
|
||||
** used in the estimate, X would have "200 2" and Y would have "200 10"
|
||||
** and so the planner would think X is the more selective index. And
|
||||
** X often would be more selective. But when searching for 0, index X
|
||||
** would perform badly. To avoid this problem, the M is added into the
|
||||
** estimate so that the stat for X is "200 34" and Y is still "200 10".
|
||||
** In this way, Y is the preferred index (all else being equal) and
|
||||
** the pathological case is avoided.
|
||||
**
|
||||
** For deciding whether or not to do a skip-scan, we want to know the
|
||||
** average number of rows (V) with the same key, not the mixed estimate
|
||||
** E shown above. Usually E will be close enough. However, if E is
|
||||
** large but V is small, that could trick the query planner into thinking
|
||||
** that a skip-scan might work well on this index. To avoid that, the
|
||||
** "noskipscan" flag is added in cases where the divergence between E
|
||||
** and V might mislead the query planner.
|
||||
*/
|
||||
char *z;
|
||||
int i;
|
||||
int noSkipScan = 0;
|
||||
|
||||
char *zRet = sqlite3MallocZero( (p->nKeyCol+1)*25 );
|
||||
char *zRet = sqlite3MallocZero( (p->nKeyCol+2)*25 );
|
||||
if( zRet==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
@@ -854,14 +883,18 @@ static void statGet(
|
||||
sqlite3_snprintf(24, zRet, "%llu", (u64)p->nRow);
|
||||
z = zRet + sqlite3Strlen30(zRet);
|
||||
for(i=0; i<p->nKeyCol; i++){
|
||||
u64 nDistinct = p->current.anDLt[i] + 1;
|
||||
u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
|
||||
u64 nDistinct = p->current.anDLt[i];
|
||||
u64 iMx = p->current.amxEq[i]; /* M: Most rows per key */
|
||||
u64 iAvg = (p->nRow+nDistinct)/(nDistinct+1); /* V: Average per key */
|
||||
u64 iVal = (iMx+iAvg*2)/3; /* E: The estimate */
|
||||
sqlite3_snprintf(24, z, " %llu", iVal);
|
||||
z += sqlite3Strlen30(z);
|
||||
assert( p->current.anEq[i] );
|
||||
if( iVal>=WHERE_SKIPSCAN_ONSET && iAvg<(WHERE_SKIPSCAN_ONSET*2/3) ){
|
||||
noSkipScan = 1;
|
||||
}
|
||||
}
|
||||
assert( z[0]=='\0' && z>zRet );
|
||||
|
||||
if( noSkipScan ) sqlite3_snprintf(14, z, " noskipscan");
|
||||
sqlite3_result_text(context, zRet, -1, sqlite3_free);
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
@@ -1571,52 +1604,45 @@ void sqlite3DeleteIndexSamples(sqlite3 *db, Index *pIdx){
|
||||
*/
|
||||
static void initAvgEq(Index *pIdx){
|
||||
if( pIdx ){
|
||||
IndexSample *aSample = pIdx->aSample;
|
||||
IndexSample *pFinal = &aSample[pIdx->nSample-1];
|
||||
int iCol;
|
||||
int nCol = 1;
|
||||
if( pIdx->nSampleCol>1 ){
|
||||
int nSample = pIdx->nSample; /* Number of samples */
|
||||
int nCol = pIdx->nSampleCol; /* Number of columns sampled */
|
||||
IndexSample *aSample = pIdx->aSample; /* The samples */
|
||||
IndexSample *pFinal = &aSample[nSample-1]; /* The last sample */
|
||||
int iCol; /* Loop counter of columns */
|
||||
if( nCol>1 ){
|
||||
/* If this is stat4 data, then calculate aAvgEq[] values for all
|
||||
** sample columns except the last. The last is always set to 1, as
|
||||
** once the trailing PK fields are considered all index keys are
|
||||
** unique. */
|
||||
nCol = pIdx->nSampleCol-1;
|
||||
nCol--;
|
||||
pIdx->aAvgEq[nCol] = 1;
|
||||
}
|
||||
for(iCol=0; iCol<nCol; iCol++){
|
||||
int nSample = pIdx->nSample;
|
||||
int i; /* Used to iterate through samples */
|
||||
u32 nDSample = 0; /* Number of distinct samples less than pFinal*/
|
||||
tRowcnt sumEq = 0; /* Sum of the nEq values */
|
||||
tRowcnt avgEq = 0;
|
||||
tRowcnt avgEq; /* Average repeats for unsampled entries */
|
||||
tRowcnt nRow; /* Number of rows in index */
|
||||
i64 nSum100 = 0; /* Number of terms contributing to sumEq */
|
||||
i64 nDist100; /* Number of distinct values in index */
|
||||
tRowcnt prevLt = 0; /* Number of values less than previous sample */
|
||||
tRowcnt thisLt; /* Number of values less than current sample */
|
||||
|
||||
if( !pIdx->aiRowEst || iCol>=pIdx->nKeyCol || pIdx->aiRowEst[iCol+1]==0 ){
|
||||
nRow = pFinal->anLt[iCol];
|
||||
nDist100 = (i64)100 * pFinal->anDLt[iCol];
|
||||
nSample--;
|
||||
nRow = pFinal->anLt[iCol] + pFinal->anEq[iCol];
|
||||
}else{
|
||||
nRow = pIdx->aiRowEst[0];
|
||||
nDist100 = ((i64)100 * pIdx->aiRowEst[0]) / pIdx->aiRowEst[iCol+1];
|
||||
}
|
||||
pIdx->nRowEst0 = nRow;
|
||||
|
||||
/* Set nSum to the number of distinct (iCol+1) field prefixes that
|
||||
** occur in the stat4 table for this index. Set sumEq to the sum of
|
||||
** the nEq values for column iCol for the same set (adding the value
|
||||
** only once where there exist duplicate prefixes). */
|
||||
for(i=0; i<nSample; i++){
|
||||
if( i==(pIdx->nSample-1)
|
||||
|| aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol]
|
||||
){
|
||||
for(i=0; (thisLt = aSample[i].anLt[iCol])<pFinal->anLt[iCol]; i++){
|
||||
if( i==0 || thisLt!=prevLt ){
|
||||
sumEq += aSample[i].anEq[iCol];
|
||||
nSum100 += 100;
|
||||
nDSample++;
|
||||
}
|
||||
prevLt = thisLt;
|
||||
}
|
||||
|
||||
if( nDist100>nSum100 ){
|
||||
avgEq = ((i64)100 * (nRow - sumEq))/(nDist100 - nSum100);
|
||||
if( pFinal->anDLt[iCol] > nDSample ){
|
||||
avgEq = (pFinal->anLt[iCol] - sumEq)/(pFinal->anDLt[iCol] - nDSample);
|
||||
}else{
|
||||
avgEq = 1;
|
||||
}
|
||||
if( avgEq==0 ) avgEq = 1;
|
||||
pIdx->aAvgEq[iCol] = avgEq;
|
||||
|
||||
@@ -2421,6 +2421,15 @@ struct SrcList {
|
||||
#define JT_OUTER 0x0020 /* The "OUTER" keyword is present */
|
||||
#define JT_ERROR 0x0040 /* unknown or unsupported join type */
|
||||
|
||||
/*
|
||||
** TUNING: The skip-scan optimization is only profitable if the average
|
||||
** number of repeats of an entry in the index is greater than or equal to
|
||||
** WHERE_SKIPSCAN_ONSET. If the average numbe of repeats is less
|
||||
** than WHERE_SKIPSCAN_ONSET, then it is faster to do a full table
|
||||
** scan.
|
||||
*/
|
||||
#define WHERE_SKIPSCAN_ONSET 18
|
||||
#define WHERE_SKIPSCAN_ONSET_LOG 42
|
||||
|
||||
/*
|
||||
** Flags appropriate for the wctrlFlags parameter of sqlite3WhereBegin()
|
||||
|
||||
+2
-2
@@ -2412,11 +2412,11 @@ static int whereLoopAddBtreeIndex(
|
||||
** 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) );
|
||||
assert( WHERE_SKIPSCAN_ONSET_LOG==sqlite3LogEst(WHERE_SKIPSCAN_ONSET) );
|
||||
if( saved_nEq==saved_nSkip
|
||||
&& saved_nEq+1<pProbe->nKeyCol
|
||||
&& pProbe->noSkipScan==0
|
||||
&& pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
|
||||
&& pProbe->aiRowLogEst[saved_nEq+1]>=WHERE_SKIPSCAN_ONSET_LOG
|
||||
&& (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
|
||||
){
|
||||
LogEst nIter;
|
||||
|
||||
+30
-62
@@ -48,22 +48,16 @@ do_execsql_test skipscan2-1.2 {
|
||||
INSERT INTO people VALUES('Robert','student',159);
|
||||
INSERT INTO people VALUES('Sally','student',166);
|
||||
INSERT INTO people VALUES('Tom','student',171);
|
||||
INSERT INTO people VALUES('Ursula','student',170);
|
||||
INSERT INTO people VALUES('Vance','student',179);
|
||||
INSERT INTO people VALUES('Willma','student',175);
|
||||
INSERT INTO people VALUES('Xavier','teacher',185);
|
||||
INSERT INTO people VALUES('Yvonne','student',149);
|
||||
INSERT INTO people VALUES('Zach','student',170);
|
||||
}
|
||||
|
||||
# Without ANALYZE, a skip-scan is not used
|
||||
#
|
||||
do_execsql_test skipscan2-1.3 {
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
SELECT name FROM people WHERE height<=161 ORDER BY +name;
|
||||
} {Alice Bob Cindy Emily Megan Olivia Robert}
|
||||
do_execsql_test skipscan2-1.3eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
SELECT name FROM people WHERE height<=161 ORDER BY +name;
|
||||
} {~/*INDEX people_idx1 */}
|
||||
|
||||
# Now do an ANALYZE. A skip-scan can be used after ANALYZE.
|
||||
@@ -79,11 +73,11 @@ do_execsql_test skipscan2-1.4 {
|
||||
}
|
||||
db cache flush
|
||||
do_execsql_test skipscan2-1.5 {
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
SELECT name FROM people WHERE height<=161 ORDER BY +name;
|
||||
} {Alice Bob Cindy Emily Megan Olivia Robert}
|
||||
do_execsql_test skipscan2-1.5eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
SELECT name FROM people WHERE height<=161 ORDER BY +name;
|
||||
} {/*INDEX people_idx1 */}
|
||||
|
||||
# Same answer with other formulations of the same query
|
||||
@@ -91,59 +85,33 @@ do_execsql_test skipscan2-1.5eqp {
|
||||
do_execsql_test skipscan2-1.6 {
|
||||
SELECT name FROM people
|
||||
WHERE role IN (SELECT DISTINCT role FROM people)
|
||||
AND height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
AND height<=161 ORDER BY +name;
|
||||
} {Alice Bob Cindy Emily Megan Olivia Robert}
|
||||
do_execsql_test skipscan2-1.7 {
|
||||
SELECT name FROM people WHERE role='teacher' AND height>=180
|
||||
SELECT name FROM people WHERE role='teacher' AND height<=161
|
||||
UNION ALL
|
||||
SELECT name FROM people WHERE role='student' AND height>=180
|
||||
SELECT name FROM people WHERE role='student' AND height<=161
|
||||
ORDER BY 1;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
} {Alice Bob Cindy Emily Megan Olivia Robert}
|
||||
|
||||
# Add 8 more people, bringing the total to 34. Then the number of
|
||||
# duplicates in the left-column of the index will be 17 and
|
||||
# skip-scan should not be used after an (unfudged) ANALYZE.
|
||||
# Add more people so that the estimated number of rows per key is
|
||||
# equal to the skip-scan threshold of 18. Then run an (unfudged)
|
||||
# ANALYZE. skip-scan should work.
|
||||
#
|
||||
do_execsql_test skipscan2-1.8 {
|
||||
INSERT INTO people VALUES('Angie','student',166);
|
||||
INSERT INTO people VALUES('Brad','student',176);
|
||||
INSERT INTO people VALUES('Claire','student',168);
|
||||
INSERT INTO people VALUES('Donald','student',162);
|
||||
INSERT INTO people VALUES('Elaine','student',177);
|
||||
INSERT INTO people VALUES('Frazier','student',159);
|
||||
INSERT INTO people VALUES('Grace','student',179);
|
||||
INSERT INTO people VALUES('Horace','student',166);
|
||||
INSERT INTO people VALUES('Ursula','student',170);
|
||||
ANALYZE;
|
||||
SELECT stat FROM sqlite_stat1 WHERE idx='people_idx1';
|
||||
} {{34 17 2}}
|
||||
} {{21 13 2}}
|
||||
db cache flush
|
||||
do_execsql_test skipscan2-1.9 {
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
SELECT name FROM people WHERE height<=161 ORDER BY +name;
|
||||
} {Alice Bob Cindy Emily Megan Olivia Robert}
|
||||
do_execsql_test skipscan2-1.9eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
SELECT name FROM people WHERE height<=161 ORDER BY +name;
|
||||
} {~/*INDEX people_idx1 */}
|
||||
|
||||
# Add 2 more people, bringing the total to 36. Then the number of
|
||||
# duplicates in the left-column of the index will be 18 and
|
||||
# skip-scan will be used after an (unfudged) ANALYZE.
|
||||
#
|
||||
do_execsql_test skipscan2-1.10 {
|
||||
INSERT INTO people VALUES('Ingrad','student',155);
|
||||
INSERT INTO people VALUES('Jacob','student',179);
|
||||
ANALYZE;
|
||||
SELECT stat FROM sqlite_stat1 WHERE idx='people_idx1';
|
||||
} {{36 18 2}}
|
||||
db cache flush
|
||||
do_execsql_test skipscan2-1.11 {
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-1.11eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {/*INDEX people_idx1 */}
|
||||
|
||||
|
||||
# Repeat using a WITHOUT ROWID table.
|
||||
#
|
||||
@@ -158,19 +126,19 @@ do_execsql_test skipscan2-2.1 {
|
||||
INSERT INTO peoplew(name,role,height)
|
||||
SELECT name, role, height FROM people;
|
||||
ALTER TABLE people RENAME TO old_people;
|
||||
SELECT name FROM peoplew WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
SELECT name FROM peoplew WHERE height<=161 ORDER BY +name;
|
||||
} {Alice Bob Cindy Emily Megan Olivia Robert}
|
||||
do_execsql_test skipscan2-2.2 {
|
||||
SELECT name FROM peoplew
|
||||
WHERE role IN (SELECT DISTINCT role FROM peoplew)
|
||||
AND height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
AND height<=161 ORDER BY +name;
|
||||
} {Alice Bob Cindy Emily Megan Olivia Robert}
|
||||
do_execsql_test skipscan2-2.2 {
|
||||
SELECT name FROM peoplew WHERE role='teacher' AND height>=180
|
||||
SELECT name FROM peoplew WHERE role='teacher' AND height<=161
|
||||
UNION ALL
|
||||
SELECT name FROM peoplew WHERE role='student' AND height>=180
|
||||
SELECT name FROM peoplew WHERE role='student' AND height<=161
|
||||
ORDER BY 1;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
} {Alice Bob Cindy Emily Megan Olivia Robert}
|
||||
|
||||
# Now do an ANALYZE. A skip-scan can be used after ANALYZE.
|
||||
#
|
||||
@@ -179,12 +147,12 @@ do_execsql_test skipscan2-2.4 {
|
||||
}
|
||||
db cache flush
|
||||
do_execsql_test skipscan2-2.5 {
|
||||
SELECT name FROM peoplew WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
SELECT name FROM peoplew WHERE height<=161 ORDER BY +name;
|
||||
} {Alice Bob Cindy Emily Megan Olivia Robert}
|
||||
do_execsql_test skipscan2-2.5eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM peoplew WHERE height>=180 ORDER BY +name;
|
||||
} {/*INDEX peoplew_idx1 */}
|
||||
SELECT name FROM peoplew WHERE height<=161 ORDER BY +name;
|
||||
} {/*INDEX peoplew_idx1*/}
|
||||
|
||||
# A skip-scan on a PK index of a WITHOUT ROWID table.
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user