mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Further testing and bug fixing for sqlite_stat3. Added the Index.avgEq
field to index statistics. Fixed several problems in the query planner associated with stat3. FossilOrigin-Name: 89b2f70884cad0abdf4c66cb64ecddb2820ded74
This commit is contained in:
32
manifest
32
manifest
@ -1,5 +1,5 @@
|
||||
C Add\sthe\ssqlite_stat3.nDLT\sfield.\s\sUse\san\slinear\scongruence\sPRNG\sto\schoose\nwhich\ssamples\sto\sselect\sfrom\samong\sthose\swith\sthe\ssame\snEq\sfield.
|
||||
D 2011-08-13T15:25:10.607
|
||||
C Further\stesting\sand\sbug\sfixing\sfor\ssqlite_stat3.\s\sAdded\sthe\sIndex.avgEq\nfield\sto\sindex\sstatistics.\s\sFixed\sseveral\sproblems\sin\sthe\squery\splanner\nassociated\swith\sstat3.
|
||||
D 2011-08-13T19:35:19.088
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 1e6988b3c11dee9bd5edc0c804bd4468d74a9cdc
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -118,7 +118,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c ac80a0f31189f8b4a524ebf661e47e84536ee7f5
|
||||
F src/analyze.c 6901cc6e91cc6d4a6b584025f58ec2839783b6c3
|
||||
F src/analyze.c c04d95f4dc82b94250c4053ca36cc52b42f257ea
|
||||
F src/attach.c 12c6957996908edc31c96d7c68d4942c2474405f
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 986c15232757f2873dff35ee3b35cbf935fc573c
|
||||
@ -127,7 +127,7 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 8c46f0ab69ad9549c75a3a91fed87abdaa743e2f
|
||||
F src/btree.h f5d775cd6cfc7ac32a2535b70e8d2af48ef5f2ce
|
||||
F src/btreeInt.h 67978c014fa4f7cc874032dd3aacadd8db656bc3
|
||||
F src/build.c 4165efa323b4d3678a6b39fddb775627c18e9a80
|
||||
F src/build.c cd77ae979219d6363234b506de28c71f217063e1
|
||||
F src/callback.c 0425c6320730e6d3981acfb9202c1bed9016ad1a
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 0df87f944b17c17c6b3976a9758d8af2802e1b19
|
||||
@ -183,7 +183,7 @@ F src/select.c d219c4b68d603cc734b6f9b1e2780fee12a1fa0d
|
||||
F src/shell.c bbe7818ff5bc8614105ceb81ad67b8bdc0b671dd
|
||||
F src/sqlite.h.in e8eb090406b9a743befff4c387aa3bd5eeae661e
|
||||
F src/sqlite3ext.h 1a1a4f784aa9c3b00edd287940197de52487cd93
|
||||
F src/sqliteInt.h a4c0124ff6dbbf325002b4a34248cc08453c9739
|
||||
F src/sqliteInt.h f491be51e47267ae1454317fbd3438382e60fdb3
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@ -250,7 +250,7 @@ F src/vtab.c 901791a47318c0562cd0c676a2c6ff1bc530e582
|
||||
F src/wal.c 3154756177d6219e233d84291d5b05f4e06ff5e9
|
||||
F src/wal.h 66b40bd91bc29a5be1c88ddd1f5ade8f3f48728a
|
||||
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
|
||||
F src/where.c 24d95b218176bad38ae2abe73197c28d3d6ef9a6
|
||||
F src/where.c 118896232fe70b1ac9c2ef2811675d5bef8b9c40
|
||||
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
|
||||
@ -260,13 +260,13 @@ F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060
|
||||
F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
|
||||
F test/alter4.test b2debc14d8cbe4c1d12ccd6a41eef88a8c1f15d5
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/analyze.test 68b43c1f9cd6ffc3bbb30d27a23712b38c413eca
|
||||
F test/analyze.test f8ab7d15858b4093b06caf5e57e2a5ff7104bdae
|
||||
F test/analyze2.test 8f2b1534d43f5547ce9a6b736c021d4192c75be3
|
||||
F test/analyze3.test d61f55d8b472fc6e713160b1e577f7a68e63f38b
|
||||
F test/analyze3.test d5e4da00a37b927d83aead50626c254a785c111f
|
||||
F test/analyze4.test 757b37875cf9bb528d46f74497bc789c88365045
|
||||
F test/analyze5.test 1de8d66b11aae5a1453aa042d62e834a476bac9c
|
||||
F test/analyze5.test 713354664c5ff1853ab2cbcb740f0cf5cb7c802e
|
||||
F test/analyze6.test c125622a813325bba1b4999040ddc213773c2290
|
||||
F test/analyze7.test 5508e7828164ea0b518ed219bed7320a481863d4
|
||||
F test/analyze7.test d3587aa5af75c9048d031b94fceca2534fa75d1d
|
||||
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
|
||||
F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
|
||||
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
|
||||
@ -359,7 +359,7 @@ F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
|
||||
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
|
||||
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
|
||||
F test/date.test a18a2ce81add84b17b06559e82ad7bb91bc6ddff
|
||||
F test/dbstatus.test a719af0f226bd280748a4bb9054c0a5a9fc1b16c
|
||||
F test/dbstatus.test 9eb484ba837c6f3f9bbcaecc29e6060a8c3ba6d2
|
||||
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
|
||||
F test/delete.test a065b05d2ebf60fd16639c579a4adfb7c381c701
|
||||
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
|
||||
@ -682,7 +682,7 @@ F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test 0997f6a57a35866b14111ed361ed8851ce7978ae
|
||||
F test/stat3.test 44cec64164a2f5d86960343a118bc0bdac754f61
|
||||
F test/stat3.test 986d735f70ef62a1daf98e8762f35fa3b062c5c3
|
||||
F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9
|
||||
F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
|
||||
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
@ -851,7 +851,7 @@ F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
|
||||
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
|
||||
F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2
|
||||
F test/unixexcl.test 9d80a54d86d2261f660758928959368ffc36151e
|
||||
F test/unordered.test e81169ce2a8f31b2c6b66af691887e1376ab3ced
|
||||
F test/unordered.test f53095cee37851bf30130fa1bf299a8845e837bb
|
||||
F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172
|
||||
F test/uri.test 53de9a2549cbda9c343223236918ef502f6a9051
|
||||
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
@ -958,7 +958,7 @@ F tool/symbols.sh caaf6ccc7300fd43353318b44524853e222557d5
|
||||
F tool/tostr.awk 11760e1b94a5d3dcd42378f3cc18544c06cfa576
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
F tool/warnings.sh 2ebae31e1eb352696f3c2f7706a34c084b28c262
|
||||
P 8225924ea015a0c331b69134139922ec83f989f8
|
||||
R 26e2ba931d588fb68b0f6f40c6d0c97e
|
||||
P 1dcd24283e6c1cc638eb9ffac434046447f88769
|
||||
R d1b65b54090c71db8593e348e48cfb27
|
||||
U drh
|
||||
Z 3074616e4d36d00fd7fabd4dfdb13fe0
|
||||
Z 11276de2d321825346f710e3928eda70
|
||||
|
@ -1 +1 @@
|
||||
1dcd24283e6c1cc638eb9ffac434046447f88769
|
||||
89b2f70884cad0abdf4c66cb64ecddb2820ded74
|
@ -957,6 +957,7 @@ static int loadStat3(sqlite3 *db, const char *zDb){
|
||||
assert( pIdx->nSample==0 );
|
||||
pIdx->nSample = (u8)nSample;
|
||||
pIdx->aSample = sqlite3MallocZero( nSample*sizeof(IndexSample) );
|
||||
pIdx->avgEq = pIdx->aiRowEst[1];
|
||||
if( pIdx->aSample==0 ){
|
||||
db->mallocFailed = 1;
|
||||
sqlite3_finalize(pStmt);
|
||||
@ -966,7 +967,7 @@ static int loadStat3(sqlite3 *db, const char *zDb){
|
||||
sqlite3_finalize(pStmt);
|
||||
|
||||
zSql = sqlite3MPrintf(db,
|
||||
"SELECT idx,nlt,neq,sample FROM %Q.sqlite_stat3", zDb);
|
||||
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat3", zDb);
|
||||
if( !zSql ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
@ -977,6 +978,8 @@ static int loadStat3(sqlite3 *db, const char *zDb){
|
||||
while( sqlite3_step(pStmt)==SQLITE_ROW ){
|
||||
char *zIndex; /* Index name */
|
||||
Index *pIdx; /* Pointer to the index object */
|
||||
int i; /* Loop counter */
|
||||
tRowcnt sumEq; /* Sum of the nEq values */
|
||||
|
||||
zIndex = (char *)sqlite3_column_text(pStmt, 0);
|
||||
if( zIndex==0 ) continue;
|
||||
@ -990,17 +993,25 @@ static int loadStat3(sqlite3 *db, const char *zDb){
|
||||
}
|
||||
assert( idx<pIdx->nSample );
|
||||
pSample = &pIdx->aSample[idx];
|
||||
pSample->nLt = (tRowcnt)sqlite3_column_int64(pStmt, 1);
|
||||
pSample->nEq = (tRowcnt)sqlite3_column_int64(pStmt, 2);
|
||||
eType = sqlite3_column_type(pStmt, 3);
|
||||
pSample->nEq = (tRowcnt)sqlite3_column_int64(pStmt, 1);
|
||||
pSample->nLt = (tRowcnt)sqlite3_column_int64(pStmt, 2);
|
||||
pSample->nDLt = (tRowcnt)sqlite3_column_int64(pStmt, 3);
|
||||
if( idx==pIdx->nSample-1 ){
|
||||
if( pSample->nDLt>0 ){
|
||||
for(i=0, sumEq=0; i<=idx-1; i++) sumEq += pIdx->aSample[i].nEq;
|
||||
pIdx->avgEq = (pSample->nLt - sumEq)/pSample->nDLt;
|
||||
}
|
||||
if( pIdx->avgEq<=0 ) pIdx->avgEq = 1;
|
||||
}
|
||||
eType = sqlite3_column_type(pStmt, 4);
|
||||
pSample->eType = (u8)eType;
|
||||
switch( eType ){
|
||||
case SQLITE_INTEGER: {
|
||||
pSample->u.i = sqlite3_column_int64(pStmt, 3);
|
||||
pSample->u.i = sqlite3_column_int64(pStmt, 4);
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
pSample->u.r = sqlite3_column_double(pStmt, 3);
|
||||
pSample->u.r = sqlite3_column_double(pStmt, 4);
|
||||
break;
|
||||
}
|
||||
case SQLITE_NULL: {
|
||||
@ -1009,10 +1020,10 @@ static int loadStat3(sqlite3 *db, const char *zDb){
|
||||
default: assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB ); {
|
||||
const char *z = (const char *)(
|
||||
(eType==SQLITE_BLOB) ?
|
||||
sqlite3_column_blob(pStmt, 3):
|
||||
sqlite3_column_text(pStmt, 3)
|
||||
sqlite3_column_blob(pStmt, 4):
|
||||
sqlite3_column_text(pStmt, 4)
|
||||
);
|
||||
int n = sqlite3_column_bytes(pStmt, 2);
|
||||
int n = sqlite3_column_bytes(pStmt, 4);
|
||||
if( n>0xffff ) n = 0xffff;
|
||||
pSample->nByte = (u16)n;
|
||||
if( n < 1){
|
||||
|
@ -2062,7 +2062,6 @@ void sqlite3CodeDropTable(Parse *pParse, Table *pTab, int iDb, int isView){
|
||||
sqlite3NestedParse(pParse,
|
||||
"DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'",
|
||||
pDb->zName, SCHEMA_TABLE(iDb), pTab->zName);
|
||||
sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
|
||||
if( !isView && !IsVirtual(pTab) ){
|
||||
destroyTable(pParse, pTab);
|
||||
}
|
||||
@ -2174,6 +2173,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||
sqlite3FkDropTable(pParse, pName, pTab);
|
||||
sqlite3CodeDropTable(pParse, pTab, iDb, isView);
|
||||
sqlite3ClearStatTables(pParse, iDb, "tbl", pTab->zName);
|
||||
}
|
||||
|
||||
exit_drop_table:
|
||||
|
@ -1502,6 +1502,7 @@ struct Index {
|
||||
u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */
|
||||
char **azColl; /* Array of collation sequence names for index */
|
||||
#ifdef SQLITE_ENABLE_STAT3
|
||||
tRowcnt avgEq; /* Average nEq value for key values not in aSample */
|
||||
IndexSample *aSample; /* Samples of the left-most key */
|
||||
#endif
|
||||
};
|
||||
@ -1520,6 +1521,7 @@ struct IndexSample {
|
||||
u16 nByte; /* Size in byte of text or blob. */
|
||||
tRowcnt nEq; /* Est. number of rows where the key equals this sample */
|
||||
tRowcnt nLt; /* Est. number of rows where key is less than this sample */
|
||||
tRowcnt nDLt; /* Est. number of distinct keys less than this sample */
|
||||
};
|
||||
|
||||
/*
|
||||
|
59
src/where.c
59
src/where.c
@ -2441,6 +2441,8 @@ static int whereKeyStats(
|
||||
IndexSample *aSample;
|
||||
int i, eType;
|
||||
int isEq = 0;
|
||||
i64 v;
|
||||
double r, rS;
|
||||
|
||||
assert( roundUp==0 || roundUp==1 );
|
||||
if( pVal==0 ) return SQLITE_ERROR;
|
||||
@ -2450,22 +2452,36 @@ static int whereKeyStats(
|
||||
eType = sqlite3_value_type(pVal);
|
||||
|
||||
if( eType==SQLITE_INTEGER ){
|
||||
i64 v = sqlite3_value_int64(pVal);
|
||||
v = sqlite3_value_int64(pVal);
|
||||
r = (i64)v;
|
||||
for(i=0; i<pIdx->nSample; i++){
|
||||
if( aSample[i].eType==SQLITE_NULL ) continue;
|
||||
if( aSample[i].eType>=SQLITE_TEXT ) break;
|
||||
if( aSample[i].u.i>=v ){
|
||||
isEq = aSample[i].u.i==v;
|
||||
break;
|
||||
if( aSample[i].eType==SQLITE_INTEGER ){
|
||||
if( aSample[i].u.i>=v ){
|
||||
isEq = aSample[i].u.i==v;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
assert( aSample[i].eType==SQLITE_FLOAT );
|
||||
if( aSample[i].u.r>=r ){
|
||||
isEq = aSample[i].u.r==r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if( eType==SQLITE_FLOAT ){
|
||||
double r = sqlite3_value_double(pVal);
|
||||
r = sqlite3_value_double(pVal);
|
||||
for(i=0; i<pIdx->nSample; i++){
|
||||
if( aSample[i].eType==SQLITE_NULL ) continue;
|
||||
if( aSample[i].eType>=SQLITE_TEXT ) break;
|
||||
if( aSample[i].u.r>=r ){
|
||||
isEq = aSample[i].u.r==r;
|
||||
if( aSample[i].eType==SQLITE_FLOAT ){
|
||||
rS = aSample[i].u.r;
|
||||
}else{
|
||||
rS = aSample[i].u.i;
|
||||
}
|
||||
if( rS>=r ){
|
||||
isEq = rS==r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -2546,14 +2562,11 @@ static int whereKeyStats(
|
||||
if( i==0 ){
|
||||
iLower = 0;
|
||||
iUpper = aSample[0].nLt;
|
||||
}else if( i>=pIdx->nSample ){
|
||||
iUpper = n;
|
||||
iLower = aSample[i].nEq + aSample[i].nLt;
|
||||
}else{
|
||||
iUpper = i>=pIdx->nSample ? n : aSample[i].nLt;
|
||||
iLower = aSample[i-1].nEq + aSample[i-1].nLt;
|
||||
iUpper = aSample[i].nLt;
|
||||
}
|
||||
aStat[1] = pIdx->aiRowEst[1];
|
||||
aStat[1] = pIdx->avgEq;
|
||||
if( iLower>=iUpper ){
|
||||
iGap = 0;
|
||||
}else{
|
||||
@ -2651,7 +2664,7 @@ static int whereRangeScanEst(
|
||||
int nEq, /* index into p->aCol[] of the range-compared column */
|
||||
WhereTerm *pLower, /* Lower bound on the range. ex: "x>123" Might be NULL */
|
||||
WhereTerm *pUpper, /* Upper bound on the range. ex: "x<455" Might be NULL */
|
||||
tRowcnt *pRangeDiv /* OUT: Reduce search space by this divisor */
|
||||
double *pRangeDiv /* OUT: Reduce search space by this divisor */
|
||||
){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
@ -2684,18 +2697,18 @@ static int whereRangeScanEst(
|
||||
&& whereKeyStats(pParse, p, pRangeVal, 1, a)==SQLITE_OK
|
||||
){
|
||||
iUpper = a[0];
|
||||
if( pLower->eOperator==WO_LE ) iUpper += a[1];
|
||||
if( pUpper->eOperator==WO_LE ) iUpper += a[1];
|
||||
}
|
||||
sqlite3ValueFree(pRangeVal);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
if( iUpper<=iLower ){
|
||||
*pRangeDiv = p->aiRowEst[0];
|
||||
*pRangeDiv = (double)p->aiRowEst[0];
|
||||
}else{
|
||||
*pRangeDiv = p->aiRowEst[0]/(iUpper - iLower);
|
||||
*pRangeDiv = (double)p->aiRowEst[0]/(double)(iUpper - iLower);
|
||||
}
|
||||
WHERETRACE(("range scan regions: %u..%u div=%u\n",
|
||||
(u32)iLower, (u32)iUpper, (u32)*pRangeDiv));
|
||||
WHERETRACE(("range scan regions: %u..%u div=%g\n",
|
||||
(u32)iLower, (u32)iUpper, *pRangeDiv));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
@ -2705,9 +2718,9 @@ static int whereRangeScanEst(
|
||||
UNUSED_PARAMETER(nEq);
|
||||
#endif
|
||||
assert( pLower || pUpper );
|
||||
*pRangeDiv = 1;
|
||||
if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ) *pRangeDiv *= 4;
|
||||
if( pUpper ) *pRangeDiv *= 4;
|
||||
*pRangeDiv = (double)1;
|
||||
if( pLower && (pLower->wtFlags & TERM_VNULL)==0 ) *pRangeDiv *= (double)4;
|
||||
if( pUpper ) *pRangeDiv *= (double)4;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2976,7 +2989,7 @@ static void bestBtreeIndex(
|
||||
int nEq; /* Number of == or IN terms matching index */
|
||||
int bInEst = 0; /* True if "x IN (SELECT...)" seen */
|
||||
int nInMul = 1; /* Number of distinct equalities to lookup */
|
||||
tRowcnt rangeDiv = 1; /* Estimated reduction in search space */
|
||||
double rangeDiv = (double)1; /* Estimated reduction in search space */
|
||||
int nBound = 0; /* Number of range constraints seen */
|
||||
int bSort = !!pOrderBy; /* True if external sort required */
|
||||
int bDist = !!pDistinct; /* True if index cannot help with DISTINCT */
|
||||
@ -3111,7 +3124,7 @@ static void bestBtreeIndex(
|
||||
/* Adjust the number of output rows and downward to reflect rows
|
||||
** that are excluded by range constraints.
|
||||
*/
|
||||
nRow = nRow/(double)rangeDiv;
|
||||
nRow = nRow/rangeDiv;
|
||||
if( nRow<1 ) nRow = 1;
|
||||
|
||||
/* Experiments run on real SQLite databases show that the time needed
|
||||
|
@ -288,7 +288,7 @@ do_test analyze-4.3 {
|
||||
} {}
|
||||
|
||||
# Verify that DROP TABLE and DROP INDEX remove entries from the
|
||||
# sqlite_stat1 and sqlite_stat2 tables.
|
||||
# sqlite_stat1 and sqlite_stat3 tables.
|
||||
#
|
||||
do_test analyze-5.0 {
|
||||
execsql {
|
||||
@ -306,11 +306,11 @@ do_test analyze-5.0 {
|
||||
SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
|
||||
}
|
||||
} {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4}
|
||||
ifcapable stat2 {
|
||||
ifcapable stat3 {
|
||||
do_test analyze-5.1 {
|
||||
execsql {
|
||||
SELECT DISTINCT idx FROM sqlite_stat2 ORDER BY 1;
|
||||
SELECT DISTINCT tbl FROM sqlite_stat2 ORDER BY 1;
|
||||
SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1;
|
||||
SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1;
|
||||
}
|
||||
} {t3i1 t3i2 t3i3 t4i1 t4i2 t3 t4}
|
||||
}
|
||||
@ -321,11 +321,11 @@ do_test analyze-5.2 {
|
||||
SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
|
||||
}
|
||||
} {t3i1 t3i3 t4i1 t4i2 t3 t4}
|
||||
ifcapable stat2 {
|
||||
ifcapable stat3 {
|
||||
do_test analyze-5.3 {
|
||||
execsql {
|
||||
SELECT DISTINCT idx FROM sqlite_stat2 ORDER BY 1;
|
||||
SELECT DISTINCT tbl FROM sqlite_stat2 ORDER BY 1;
|
||||
SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1;
|
||||
SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1;
|
||||
}
|
||||
} {t3i1 t3i3 t4i1 t4i2 t3 t4}
|
||||
}
|
||||
@ -336,11 +336,11 @@ do_test analyze-5.4 {
|
||||
SELECT DISTINCT tbl FROM sqlite_stat1 ORDER BY 1;
|
||||
}
|
||||
} {t4i1 t4i2 t4}
|
||||
ifcapable stat2 {
|
||||
ifcapable stat3 {
|
||||
do_test analyze-5.5 {
|
||||
execsql {
|
||||
SELECT DISTINCT idx FROM sqlite_stat2 ORDER BY 1;
|
||||
SELECT DISTINCT tbl FROM sqlite_stat2 ORDER BY 1;
|
||||
SELECT DISTINCT idx FROM sqlite_stat3 ORDER BY 1;
|
||||
SELECT DISTINCT tbl FROM sqlite_stat3 ORDER BY 1;
|
||||
}
|
||||
} {t4i1 t4i2 t4}
|
||||
}
|
||||
|
@ -97,10 +97,10 @@ do_test analyze3-1.1.1 {
|
||||
|
||||
do_eqp_test analyze3-1.1.2 {
|
||||
SELECT sum(y) FROM t1 WHERE x>200 AND x<300
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?) (~100 rows)}}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?) (~179 rows)}}
|
||||
do_eqp_test analyze3-1.1.3 {
|
||||
SELECT sum(y) FROM t1 WHERE x>0 AND x<1100
|
||||
} {0 0 0 {SCAN TABLE t1 (~111 rows)}}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? and x<?) {~959 rows)}}
|
||||
|
||||
do_test analyze3-1.1.4 {
|
||||
sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 }
|
||||
@ -193,7 +193,7 @@ do_test analyze3-1.3.1 {
|
||||
} {}
|
||||
do_eqp_test analyze3-1.3.2 {
|
||||
SELECT sum(y) FROM t3 WHERE x>200 AND x<300
|
||||
} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?) (~100 rows)}}
|
||||
} {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?) (~166 rows)}}
|
||||
do_eqp_test analyze3-1.3.3 {
|
||||
SELECT sum(y) FROM t3 WHERE x>0 AND x<1100
|
||||
} {0 0 0 {SCAN TABLE t3 (~111 rows)}}
|
||||
@ -248,7 +248,7 @@ do_test analyze3-2.1 {
|
||||
} {}
|
||||
do_eqp_test analyze3-2.2 {
|
||||
SELECT count(a) FROM t1 WHERE b LIKE 'a%'
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?) (~30000 rows)}}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?) (~31250 rows)}}
|
||||
do_eqp_test analyze3-2.3 {
|
||||
SELECT count(a) FROM t1 WHERE b LIKE '%a'
|
||||
} {0 0 0 {SCAN TABLE t1 (~500000 rows)}}
|
||||
|
@ -10,14 +10,14 @@
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file implements tests for SQLite library. The focus of the tests
|
||||
# in this file is the use of the sqlite_stat2 histogram data on tables
|
||||
# in this file is the use of the sqlite_stat3 histogram data on tables
|
||||
# with many repeated values and only a few distinct values.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !stat2 {
|
||||
ifcapable !stat3 {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
@ -55,114 +55,102 @@ do_test analyze5-1.0 {
|
||||
CREATE INDEX t1y ON t1(y); -- integers 0 and very few 1s
|
||||
CREATE INDEX t1z ON t1(z); -- integers 0, 1, 2, and 3
|
||||
ANALYZE;
|
||||
SELECT sample FROM sqlite_stat2 WHERE idx='t1u' ORDER BY sampleno;
|
||||
SELECT sample FROM sqlite_stat3 WHERE idx='t1u' ORDER BY nlt;
|
||||
}
|
||||
} {alpha alpha alpha alpha bravo bravo bravo charlie charlie delta}
|
||||
do_test analyze5-1.1 {
|
||||
string tolower \
|
||||
[db eval {SELECT sample from sqlite_stat2 WHERE idx='t1v' ORDER BY sampleno}]
|
||||
} {alpha alpha alpha alpha bravo bravo bravo charlie charlie delta}
|
||||
do_test analyze5-1.2 {
|
||||
db eval {SELECT sample from sqlite_stat2 WHERE idx='t1w' ORDER BY sampleno}
|
||||
} {{} 0 0 0 0 1 1 1 2 2}
|
||||
do_test analyze5-1.3 {
|
||||
db eval {SELECT sample from sqlite_stat2 WHERE idx='t1x' ORDER BY sampleno}
|
||||
} {{} {} {} {} 1 1 1 2 2 3}
|
||||
do_test analyze5-1.4 {
|
||||
db eval {SELECT sample from sqlite_stat2 WHERE idx='t1y' ORDER BY sampleno}
|
||||
} {0 0 0 0 0 0 0 0 0 0}
|
||||
do_test analyze5-1.5 {
|
||||
db eval {SELECT sample from sqlite_stat2 WHERE idx='t1z' ORDER BY sampleno}
|
||||
} {0 0 0 0 1 1 1 2 2 3}
|
||||
do_test analyze5-1.6 {
|
||||
db eval {SELECT sample from sqlite_stat2 WHERE idx='t1t' ORDER BY sampleno}
|
||||
} {0.5 0.5 0.5 0.5 1.5 1.5 1.5 2.5 2.5 3.5}
|
||||
} {alpha bravo charlie delta}
|
||||
|
||||
do_test analyze5-1.1 {
|
||||
db eval {SELECT DISTINCT lower(sample) FROM sqlite_stat3 WHERE idx='t1v'
|
||||
ORDER BY 1}
|
||||
} {alpha bravo charlie delta}
|
||||
do_test analyze5-1.2 {
|
||||
db eval {SELECT idx, count(*) FROM sqlite_stat3 GROUP BY 1 ORDER BY 1}
|
||||
} {t1t 4 t1u 4 t1v 4 t1w 4 t1x 4 t1y 2 t1z 4}
|
||||
|
||||
# Verify that range queries generate the correct row count estimates
|
||||
#
|
||||
foreach {testid where index rows} {
|
||||
1 {z>=0 AND z<=0} t1z 400
|
||||
2 {z>=1 AND z<=1} t1z 300
|
||||
3 {z>=2 AND z<=2} t1z 200
|
||||
4 {z>=3 AND z<=3} t1z 100
|
||||
5 {z>=4 AND z<=4} t1z 50
|
||||
6 {z>=-1 AND z<=-1} t1z 50
|
||||
7 {z>1 AND z<3} t1z 200
|
||||
3 {z>=2 AND z<=2} t1z 175
|
||||
4 {z>=3 AND z<=3} t1z 125
|
||||
5 {z>=4 AND z<=4} t1z 1
|
||||
6 {z>=-1 AND z<=-1} t1z 1
|
||||
7 {z>1 AND z<3} t1z 175
|
||||
8 {z>0 AND z<100} t1z 600
|
||||
9 {z>=1 AND z<100} t1z 600
|
||||
10 {z>1 AND z<100} t1z 300
|
||||
11 {z>=2 AND z<100} t1z 300
|
||||
12 {z>2 AND z<100} t1z 100
|
||||
13 {z>=3 AND z<100} t1z 100
|
||||
14 {z>3 AND z<100} t1z 50
|
||||
15 {z>=4 AND z<100} t1z 50
|
||||
16 {z>=-100 AND z<=-1} t1z 50
|
||||
12 {z>2 AND z<100} t1z 125
|
||||
13 {z>=3 AND z<100} t1z 125
|
||||
14 {z>3 AND z<100} t1z 1
|
||||
15 {z>=4 AND z<100} t1z 1
|
||||
16 {z>=-100 AND z<=-1} t1z 1
|
||||
17 {z>=-100 AND z<=0} t1z 400
|
||||
18 {z>=-100 AND z<0} t1z 50
|
||||
18 {z>=-100 AND z<0} t1z 1
|
||||
19 {z>=-100 AND z<=1} t1z 700
|
||||
20 {z>=-100 AND z<2} t1z 700
|
||||
21 {z>=-100 AND z<=2} t1z 900
|
||||
22 {z>=-100 AND z<3} t1z 900
|
||||
21 {z>=-100 AND z<=2} t1z 875
|
||||
22 {z>=-100 AND z<3} t1z 875
|
||||
|
||||
31 {z>=0.0 AND z<=0.0} t1z 400
|
||||
32 {z>=1.0 AND z<=1.0} t1z 300
|
||||
33 {z>=2.0 AND z<=2.0} t1z 200
|
||||
34 {z>=3.0 AND z<=3.0} t1z 100
|
||||
35 {z>=4.0 AND z<=4.0} t1z 50
|
||||
36 {z>=-1.0 AND z<=-1.0} t1z 50
|
||||
37 {z>1.5 AND z<3.0} t1z 200
|
||||
38 {z>0.5 AND z<100} t1z 600
|
||||
33 {z>=2.0 AND z<=2.0} t1z 175
|
||||
34 {z>=3.0 AND z<=3.0} t1z 125
|
||||
35 {z>=4.0 AND z<=4.0} t1z 1
|
||||
36 {z>=-1.0 AND z<=-1.0} t1z 1
|
||||
37 {z>1.5 AND z<3.0} t1z 174
|
||||
38 {z>0.5 AND z<100} t1z 599
|
||||
39 {z>=1.0 AND z<100} t1z 600
|
||||
40 {z>1.5 AND z<100} t1z 300
|
||||
40 {z>1.5 AND z<100} t1z 299
|
||||
41 {z>=2.0 AND z<100} t1z 300
|
||||
42 {z>2.1 AND z<100} t1z 100
|
||||
43 {z>=3.0 AND z<100} t1z 100
|
||||
44 {z>3.2 AND z<100} t1z 50
|
||||
45 {z>=4.0 AND z<100} t1z 50
|
||||
46 {z>=-100 AND z<=-1.0} t1z 50
|
||||
42 {z>2.1 AND z<100} t1z 124
|
||||
43 {z>=3.0 AND z<100} t1z 125
|
||||
44 {z>3.2 AND z<100} t1z 1
|
||||
45 {z>=4.0 AND z<100} t1z 1
|
||||
46 {z>=-100 AND z<=-1.0} t1z 1
|
||||
47 {z>=-100 AND z<=0.0} t1z 400
|
||||
48 {z>=-100 AND z<0.0} t1z 50
|
||||
48 {z>=-100 AND z<0.0} t1z 1
|
||||
49 {z>=-100 AND z<=1.0} t1z 700
|
||||
50 {z>=-100 AND z<2.0} t1z 700
|
||||
51 {z>=-100 AND z<=2.0} t1z 900
|
||||
52 {z>=-100 AND z<3.0} t1z 900
|
||||
51 {z>=-100 AND z<=2.0} t1z 875
|
||||
52 {z>=-100 AND z<3.0} t1z 875
|
||||
|
||||
101 {z=-1} t1z 50
|
||||
101 {z=-1} t1z 1
|
||||
102 {z=0} t1z 400
|
||||
103 {z=1} t1z 300
|
||||
104 {z=2} t1z 200
|
||||
105 {z=3} t1z 100
|
||||
106 {z=4} t1z 50
|
||||
107 {z=-10.0} t1z 50
|
||||
104 {z=2} t1z 175
|
||||
105 {z=3} t1z 125
|
||||
106 {z=4} t1z 1
|
||||
107 {z=-10.0} t1z 1
|
||||
108 {z=0.0} t1z 400
|
||||
109 {z=1.0} t1z 300
|
||||
110 {z=2.0} t1z 200
|
||||
111 {z=3.0} t1z 100
|
||||
112 {z=4.0} t1z 50
|
||||
113 {z=1.5} t1z 50
|
||||
114 {z=2.5} t1z 50
|
||||
110 {z=2.0} t1z 175
|
||||
111 {z=3.0} t1z 125
|
||||
112 {z=4.0} t1z 1
|
||||
113 {z=1.5} t1z 1
|
||||
114 {z=2.5} t1z 1
|
||||
|
||||
201 {z IN (-1)} t1z 50
|
||||
201 {z IN (-1)} t1z 1
|
||||
202 {z IN (0)} t1z 400
|
||||
203 {z IN (1)} t1z 300
|
||||
204 {z IN (2)} t1z 200
|
||||
205 {z IN (3)} t1z 100
|
||||
206 {z IN (4)} t1z 50
|
||||
207 {z IN (0.5)} t1z 50
|
||||
204 {z IN (2)} t1z 175
|
||||
205 {z IN (3)} t1z 125
|
||||
206 {z IN (4)} t1z 1
|
||||
207 {z IN (0.5)} t1z 1
|
||||
208 {z IN (0,1)} t1z 700
|
||||
209 {z IN (0,1,2)} t1z 900
|
||||
209 {z IN (0,1,2)} t1z 875
|
||||
210 {z IN (0,1,2,3)} {} 100
|
||||
211 {z IN (0,1,2,3,4,5)} {} 100
|
||||
212 {z IN (1,2)} t1z 500
|
||||
212 {z IN (1,2)} t1z 475
|
||||
213 {z IN (2,3)} t1z 300
|
||||
214 {z=3 OR z=2} t1z 300
|
||||
215 {z IN (-1,3)} t1z 150
|
||||
216 {z=-1 OR z=3} t1z 150
|
||||
215 {z IN (-1,3)} t1z 126
|
||||
216 {z=-1 OR z=3} t1z 126
|
||||
|
||||
300 {y=0} {} 100
|
||||
301 {y=1} t1y 50
|
||||
302 {y=0.1} t1y 50
|
||||
300 {y=0} t1y 974
|
||||
301 {y=1} t1y 26
|
||||
302 {y=0.1} t1y 1
|
||||
|
||||
400 {x IS NULL} t1x 400
|
||||
|
||||
@ -204,16 +192,17 @@ db eval {
|
||||
# Verify that range queries generate the correct row count estimates
|
||||
#
|
||||
foreach {testid where index rows} {
|
||||
500 {x IS NULL AND u='charlie'} t1u 20
|
||||
501 {x=1 AND u='charlie'} t1x 5
|
||||
502 {x IS NULL} {} 100
|
||||
503 {x=1} t1x 50
|
||||
504 {x IS NOT NULL} t1x 25
|
||||
500 {x IS NULL AND u='charlie'} t1u 17
|
||||
501 {x=1 AND u='charlie'} t1x 1
|
||||
502 {x IS NULL} t1x 995
|
||||
503 {x=1} t1x 1
|
||||
504 {x IS NOT NULL} t1x 2
|
||||
505 {+x IS NOT NULL} {} 500
|
||||
506 {upper(x) IS NOT NULL} {} 500
|
||||
|
||||
} {
|
||||
# Verify that the expected index is used with the expected row count
|
||||
if {$testid==50299} {breakpoint; set sqlite_where_trace 1}
|
||||
do_test analyze5-1.${testid}a {
|
||||
set x [lindex [eqp "SELECT * FROM t1 WHERE $where"] 3]
|
||||
set idx {}
|
||||
@ -221,6 +210,7 @@ foreach {testid where index rows} {
|
||||
regexp {~([0-9]+) rows} $x all nrow
|
||||
list $idx $nrow
|
||||
} [list $index $rows]
|
||||
if {$testid==50299} exit
|
||||
|
||||
# Verify that the same result is achieved regardless of whether or not
|
||||
# the index is used
|
||||
|
@ -82,14 +82,14 @@ do_test analyze7-3.1 {
|
||||
do_test analyze7-3.2.1 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=?;}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~86 rows)}}
|
||||
ifcapable stat2 {
|
||||
# If ENABLE_STAT2 is defined, SQLite comes up with a different estimated
|
||||
ifcapable stat3 {
|
||||
# If ENABLE_STAT3 is defined, SQLite comes up with a different estimated
|
||||
# row count for (c=2) than it does for (c=?).
|
||||
do_test analyze7-3.2.2 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~51 rows)}}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~57 rows)}}
|
||||
} else {
|
||||
# If ENABLE_STAT2 is not defined, the expected row count for (c=2) is the
|
||||
# If ENABLE_STAT3 is not defined, the expected row count for (c=2) is the
|
||||
# same as that for (c=?).
|
||||
do_test analyze7-3.2.3 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
|
||||
@ -98,12 +98,14 @@ ifcapable stat2 {
|
||||
do_test analyze7-3.3 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}}
|
||||
do_test analyze7-3.4 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~2 rows)}}
|
||||
do_test analyze7-3.5 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND c=123}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}}
|
||||
ifcapable {!stat3} {
|
||||
do_test analyze7-3.4 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~2 rows)}}
|
||||
do_test analyze7-3.5 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND c=123}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}}
|
||||
}
|
||||
do_test analyze7-3.6 {
|
||||
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND d=123 AND b=123}
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=? AND d=?) (~1 rows)}}
|
||||
|
@ -56,6 +56,12 @@ proc lookaside {db} {
|
||||
}
|
||||
}
|
||||
|
||||
ifcapable stat3 {
|
||||
set STAT3 1
|
||||
} else {
|
||||
set STAT3 0
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Run the dbstatus-2 and dbstatus-3 tests with several of different
|
||||
# lookaside buffer sizes.
|
||||
@ -118,7 +124,7 @@ foreach ::lookaside_buffer_size {0 64 120} {
|
||||
CREATE TABLE t2(c, d);
|
||||
CREATE VIEW v1 AS SELECT * FROM t1 UNION SELECT * FROM t2;
|
||||
}
|
||||
6 {
|
||||
6y {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE INDEX i1 ON t1(a);
|
||||
CREATE INDEX i2 ON t1(a,b);
|
||||
@ -198,7 +204,11 @@ foreach ::lookaside_buffer_size {0 64 120} {
|
||||
# much greater than just that reported by DBSTATUS_SCHEMA_USED in this
|
||||
# case.
|
||||
#
|
||||
if {[string match *x $tn] || $AUTOVACUUM} {
|
||||
# Some of the memory used for sqlite_stat3 is unaccounted for by
|
||||
# dbstatus.
|
||||
#
|
||||
if {[string match *x $tn] || $AUTOVACUUM
|
||||
|| ([string match *y $tn] && $STAT3)} {
|
||||
do_test dbstatus-2.$tn.ax { expr {($nSchema1-$nSchema2)<=$nFree} } 1
|
||||
} else {
|
||||
do_test dbstatus-2.$tn.a { expr {$nSchema1-$nSchema2} } $nFree
|
||||
|
@ -11,7 +11,7 @@
|
||||
#
|
||||
# This file implements regression tests for SQLite library. This file
|
||||
# implements tests for the extra functionality provided by the ANALYZE
|
||||
# command when the library is compiled with SQLITE_ENABLE_STAT2 defined.
|
||||
# command when the library is compiled with SQLITE_ENABLE_STAT3 defined.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
@ -28,7 +28,7 @@ do_test 1.1 {
|
||||
db eval {
|
||||
PRAGMA writable_schema=ON;
|
||||
CREATE TABLE sqlite_stat2(tbl,idx,sampleno,sample);
|
||||
CREATE TABLE sqlite_stat3(tbl,idx,sampleno,sample,neq,nlt);
|
||||
CREATE TABLE sqlite_stat3(tbl,idx,neq,nlt,ndlt,sample);
|
||||
SELECT name FROM sqlite_master ORDER BY 1;
|
||||
}
|
||||
} {sqlite_stat2 sqlite_stat3}
|
||||
|
@ -31,11 +31,13 @@ do_execsql_test 1.0 {
|
||||
} {}
|
||||
|
||||
foreach idxmode {ordered unordered} {
|
||||
catchsql { DELETE FROM sqlite_stat2 }
|
||||
catchsql { DELETE FROM sqlite_stat3 }
|
||||
if {$idxmode == "unordered"} {
|
||||
execsql { UPDATE sqlite_stat1 SET stat = stat || ' unordered' }
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
}
|
||||
db close
|
||||
sqlite3 db test.db
|
||||
foreach {tn sql r(ordered) r(unordered)} {
|
||||
1 "SELECT * FROM t1 ORDER BY a"
|
||||
{0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}}
|
||||
|
Reference in New Issue
Block a user