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

Further enhancements and fixes for explain query plan.

FossilOrigin-Name: 73c93f5a2a32ee8c5d07c9ba33b2641e72626627
This commit is contained in:
dan
2010-11-09 14:48:59 +00:00
parent 2ce224535f
commit 4a07e3db27
7 changed files with 174 additions and 72 deletions

View File

@@ -1,5 +1,5 @@
C Experimental\schanges\sto\sEXPLAIN\sQUERY\sPLAN. C Further\senhancements\sand\sfixes\sfor\sexplain\squery\splan.
D 2010-11-08T19:01:16 D 2010-11-09T14:49:00
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in e7a59672eaeb04408d1fa8501618d7501a3c5e39 F Makefile.in e7a59672eaeb04408d1fa8501618d7501a3c5e39
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -128,7 +128,7 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df
F src/date.c 1548fdac51377e4e7833251de878b4058c148e1b F src/date.c 1548fdac51377e4e7833251de878b4058c148e1b
F src/delete.c 7ed8a8c8b5f748ece92df173d7e0f7810c899ebd F src/delete.c 7ed8a8c8b5f748ece92df173d7e0f7810c899ebd
F src/expr.c ee36af9aa54ba841c1253edc4d9036ef47f57377 F src/expr.c 4b05c74061e9597f16bea6857b5598a8b5d5be5e
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 17950a28f28b23e8ad3feaac5fc88c324d2f600a F src/fkey.c 17950a28f28b23e8ad3feaac5fc88c324d2f600a
F src/func.c 2b7cf54d2569c2eba42fe81165d1932b546681a3 F src/func.c 2b7cf54d2569c2eba42fe81165d1932b546681a3
@@ -174,11 +174,11 @@ F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c c32d6da90895abe7ede0c18377c756d706f25e41 F src/select.c 7c92d9d06037065f4a01634d94a4e4cfc4bccf62
F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056 F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
F src/sqlite.h.in f47e09412fc9a129f759fa4d96ef21f4b3d529eb F src/sqlite.h.in f47e09412fc9a129f759fa4d96ef21f4b3d529eb
F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754 F src/sqlite3ext.h c90bd5507099f62043832d73f6425d8d5c5da754
F src/sqliteInt.h 7349903d18e2444e38414aa6da86b9d32ae1af92 F src/sqliteInt.h 8648d013cea93d204faf0959743c47bacd65a85d
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44 F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -239,7 +239,7 @@ F src/vtab.c b297e8fa656ab5e66244ab15680d68db0adbec30
F src/wal.c f26b8d297bd11cb792e609917f9d4c6718ac8e0e F src/wal.c f26b8d297bd11cb792e609917f9d4c6718ac8e0e
F src/wal.h c1aac6593a0b02b15dc625987e619edeab39292e F src/wal.h c1aac6593a0b02b15dc625987e619edeab39292e
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c ddfe0e1ac1a2c9d382b1df5bd6f9e2b0282ecc39 F src/where.c 8aded05b9845c1ed6849f0bda4e7c5723ef11624
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 6745008c144bd2956d58864d21f7b304689c1cce F test/all.test 6745008c144bd2956d58864d21f7b304689c1cce
@@ -365,7 +365,7 @@ F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
F test/enc2.test 6d91a5286f59add0cfcbb2d0da913b76f2242398 F test/enc2.test 6d91a5286f59add0cfcbb2d0da913b76f2242398
F test/enc3.test 5c550d59ff31dccdba5d1a02ae11c7047d77c041 F test/enc3.test 5c550d59ff31dccdba5d1a02ae11c7047d77c041
F test/enc4.test 4b575ef09e0eff896e73bd24076f96c2aa6a42de F test/enc4.test 4b575ef09e0eff896e73bd24076f96c2aa6a42de
F test/eqp.test d8ad22f65ad29c93708e8986c568b5b6ef043dce F test/eqp.test a63c03a35c335738ceac83cd5bf05ce622b65619
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3 F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
F test/exclusive.test 53e1841b422e554cecf0160f937c473d6d0e3062 F test/exclusive.test 53e1841b422e554cecf0160f937c473d6d0e3062
F test/exclusive2.test 76e63c05349cb70d09d60b99d2ae625525ff5155 F test/exclusive2.test 76e63c05349cb70d09d60b99d2ae625525ff5155
@@ -886,10 +886,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 65fa1164f035d270db48db6474da888aacfba3bd P f4747eb83dacce6430ad6e5eb20155ffad975514
R 5aabb390d1e5d171e6d1ec14ea681c6d R 7fc20a21ba3c9c313a6e02ede2df35d9
T *branch * experimental
T *sym-experimental *
T -sym-trunk *
U dan U dan
Z 0909e073f28cae2ed26163f9bcbdaa3d Z 5072ca13b6a16309d03aca048a4f29a7

View File

@@ -1 +1 @@
f4747eb83dacce6430ad6e5eb20155ffad975514 73c93f5a2a32ee8c5d07c9ba33b2641e72626627

View File

@@ -1600,6 +1600,16 @@ int sqlite3CodeSubselect(
assert( testAddr>0 || pParse->db->mallocFailed ); assert( testAddr>0 || pParse->db->mallocFailed );
} }
#ifndef SQLITE_OMIT_EXPLAIN
if( pParse->explain==2 ){
char *zMsg = sqlite3MPrintf(
pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr?"":"CORRELATED ",
pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId
);
sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
}
#endif
switch( pExpr->op ){ switch( pExpr->op ){
case TK_IN: { case TK_IN: {
char affinity; /* Affinity of the LHS of the IN */ char affinity; /* Affinity of the LHS of the IN */

View File

@@ -780,9 +780,11 @@ static void explainTempTable(Parse *pParse, const char *zUsage){
} }
} }
# define explainRestoreSelectId() pParse->iSelectId = iRestoreSelectId # define explainRestoreSelectId() pParse->iSelectId = iRestoreSelectId
# define explainAssignSelectId(pItem, id) pItem->iSelectId = id
#else #else
# define explainRestoreSelectId() # define explainRestoreSelectId()
# define explainTempTable(y,z) # define explainTempTable(y,z)
# define explainAssignSelectId(y,z)
#endif #endif
/* /*
@@ -3679,6 +3681,7 @@ int sqlite3Select(
}else{ }else{
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
assert( pItem->isPopulated==0 ); assert( pItem->isPopulated==0 );
explainAssignSelectId(pItem, pParse->iNextSelectId);
sqlite3Select(pParse, pSub, &dest); sqlite3Select(pParse, pSub, &dest);
pItem->isPopulated = 1; pItem->isPopulated = 1;
} }

View File

@@ -1827,6 +1827,9 @@ struct SrcList {
Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */ Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */
char *zIndex; /* Identifier from "INDEXED BY <zIndex>" clause */ char *zIndex; /* Identifier from "INDEXED BY <zIndex>" clause */
Index *pIndex; /* Index structure corresponding to zIndex, if any */ Index *pIndex; /* Index structure corresponding to zIndex, if any */
#ifndef SQLITE_OMIT_EXPLAIN
int iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */
#endif
} a[1]; /* One entry for each identifier on the list */ } a[1]; /* One entry for each identifier on the list */
}; };

View File

@@ -3165,7 +3165,8 @@ static void codeOneLoopExplain(
SrcList *pTabList, /* Table list this loop refers to */ SrcList *pTabList, /* Table list this loop refers to */
WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */
int iLevel, /* Value for "level" column of output */ int iLevel, /* Value for "level" column of output */
int iFrom /* Value for "from" column of output */ int iFrom, /* Value for "from" column of output */
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
){ ){
if( pParse->explain==2 ){ if( pParse->explain==2 ){
u32 flags = pLevel->plan.wsFlags; u32 flags = pLevel->plan.wsFlags;
@@ -3173,16 +3174,23 @@ static void codeOneLoopExplain(
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db; sqlite3 *db = pParse->db;
char *zMsg; char *zMsg;
sqlite3_int64 nRow; /* Expected number of rows visited by scan */
int iId = pParse->iSelectId; /* Select id (left-most output column) */
if( flags & WHERE_MULTI_OR ) return; if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return;
if( pItem->pSelect ){
zMsg = sqlite3MPrintf(db, "SCAN SUBQUERY %d", pItem->iSelectId);
}else{
zMsg = sqlite3MPrintf(db, "SCAN TABLE %s", pItem->zName);
}
zMsg = sqlite3MPrintf(db, "TABLE %s", pItem->zName);
if( pItem->zAlias ){ if( pItem->zAlias ){
zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias); zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias);
} }
if( (flags & WHERE_INDEXED)!=0 ){ if( (flags & WHERE_INDEXED)!=0 ){
char *zWhere = indexRangeText(db, pLevel, pItem->pTab); char *zWhere = indexRangeText(db, pLevel, pItem->pTab);
zMsg = sqlite3MAppendf(db, zMsg, "%s WITH %s%sINDEX%s%s%s", zMsg, zMsg = sqlite3MAppendf(db, zMsg, "%s BY %s%sINDEX%s%s%s", zMsg,
((flags & WHERE_TEMP_INDEX)?"AUTOMATIC ":""), ((flags & WHERE_TEMP_INDEX)?"AUTOMATIC ":""),
((flags & WHERE_IDX_ONLY)?"COVERING ":""), ((flags & WHERE_IDX_ONLY)?"COVERING ":""),
((flags & WHERE_TEMP_INDEX)?"":" "), ((flags & WHERE_TEMP_INDEX)?"":" "),
@@ -3191,7 +3199,7 @@ static void codeOneLoopExplain(
); );
sqlite3DbFree(db, zWhere); sqlite3DbFree(db, zWhere);
}else if( flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){ }else if( flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg); zMsg = sqlite3MAppendf(db, zMsg, "%s BY INTEGER PRIMARY KEY", zMsg);
if( flags&WHERE_ROWID_EQ ){ if( flags&WHERE_ROWID_EQ ){
zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg); zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg);
@@ -3210,15 +3218,17 @@ static void codeOneLoopExplain(
pVtabIdx->idxNum, pVtabIdx->idxStr); pVtabIdx->idxNum, pVtabIdx->idxStr);
} }
#endif #endif
zMsg = sqlite3MAppendf(db, zMsg, if( wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX) ){
"%s (~%lld rows)", zMsg, (sqlite3_int64)(pLevel->plan.nRow) nRow = 1;
); }else{
sqlite3VdbeAddOp4( nRow = (sqlite3_int64)pLevel->plan.nRow;
v, OP_Explain, pParse->iSelectId, iLevel, iFrom, zMsg, P4_DYNAMIC); }
zMsg = sqlite3MAppendf(db, zMsg, "%s (~%lld rows)", zMsg, nRow);
sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg, P4_DYNAMIC);
} }
} }
#else #else
# define codeOneLoopExplain(w,x,y.z) # define codeOneLoopExplain(u,v,w,x,y,z)
#endif /* SQLITE_OMIT_EXPLAIN */ #endif /* SQLITE_OMIT_EXPLAIN */
@@ -3764,7 +3774,7 @@ static Bitmask codeOneLoopStart(
WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY); WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY);
if( pSubWInfo ){ if( pSubWInfo ){
codeOneLoopExplain( codeOneLoopExplain(
pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0
); );
if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ if( (wctrlFlags & WHERE_DUPLICATES_OK)==0 ){
int iSet = ((ii==pOrWc->nTerm-1)?-1:ii); int iSet = ((ii==pOrWc->nTerm-1)?-1:ii);
@@ -4421,11 +4431,10 @@ WhereInfo *sqlite3WhereBegin(
*/ */
notReady = ~(Bitmask)0; notReady = ~(Bitmask)0;
for(i=0; i<nTabList; i++){ for(i=0; i<nTabList; i++){
if( (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){ WhereLevel *pLevel = &pWInfo->a[i];
codeOneLoopExplain(pParse, pTabList, &pWInfo->a[i],i,pWInfo->a[i].iFrom); codeOneLoopExplain(pParse, pTabList, pLevel, i, pLevel->iFrom, wctrlFlags);
}
notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady); notReady = codeOneLoopStart(pWInfo, i, wctrlFlags, notReady);
pWInfo->iContinue = pWInfo->a[i].addrCont; pWInfo->iContinue = pLevel->addrCont;
} }
#ifdef SQLITE_TEST /* For testing and debugging use only */ #ifdef SQLITE_TEST /* For testing and debugging use only */

View File

@@ -27,6 +27,7 @@ proc do_eqp_test {name sql res} {
set res [list {*}$res] set res [list {*}$res]
uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $res] uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $res]
} }
proc det {args} { uplevel do_eqp_test $args }
do_execsql_test 1.1 { do_execsql_test 1.1 {
CREATE TABLE t1(a, b); CREATE TABLE t1(a, b);
@@ -39,37 +40,37 @@ do_execsql_test 1.1 {
do_eqp_test 1.2 { do_eqp_test 1.2 {
SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2; SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2;
} { } {
0 0 1 {TABLE t1 WITH INDEX i1 (a=?) (~10 rows)} 0 0 1 {SCAN TABLE t1 BY INDEX i1 (a=?) (~10 rows)}
0 0 1 {TABLE t1 WITH INDEX i2 (b=?) (~10 rows)} 0 0 1 {SCAN TABLE t1 BY INDEX i2 (b=?) (~10 rows)}
0 1 0 {TABLE t2 (~1000000 rows)} 0 1 0 {SCAN TABLE t2 (~1000000 rows)}
} }
do_eqp_test 1.3 { do_eqp_test 1.3 {
SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2; SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2;
} { } {
0 0 0 {TABLE t2 (~1000000 rows)} 0 0 0 {SCAN TABLE t2 (~1000000 rows)}
0 1 1 {TABLE t1 WITH INDEX i1 (a=?) (~10 rows)} 0 1 1 {SCAN TABLE t1 BY INDEX i1 (a=?) (~10 rows)}
0 1 1 {TABLE t1 WITH INDEX i2 (b=?) (~10 rows)} 0 1 1 {SCAN TABLE t1 BY INDEX i2 (b=?) (~10 rows)}
} }
do_eqp_test 1.3 { do_eqp_test 1.3 {
SELECT a FROM t1 ORDER BY a SELECT a FROM t1 ORDER BY a
} { } {
0 0 0 {TABLE t1 WITH COVERING INDEX i1 (~1000000 rows)} 0 0 0 {SCAN TABLE t1 BY COVERING INDEX i1 (~1000000 rows)}
} }
do_eqp_test 1.4 { do_eqp_test 1.4 {
SELECT a FROM t1 ORDER BY +a SELECT a FROM t1 ORDER BY +a
} { } {
0 0 0 {TABLE t1 (~1000000 rows)} 0 0 0 {SCAN TABLE t1 (~1000000 rows)}
0 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}
} }
do_eqp_test 1.5 { do_eqp_test 1.5 {
SELECT a FROM t1 WHERE a=4 SELECT a FROM t1 WHERE a=4
} { } {
0 0 0 {TABLE t1 WITH COVERING INDEX i1 (a=?) (~10 rows)} 0 0 0 {SCAN TABLE t1 BY COVERING INDEX i1 (a=?) (~10 rows)}
} }
do_eqp_test 1.6 { do_eqp_test 1.6 {
SELECT DISTINCT count(*) FROM t3 GROUP BY a; SELECT DISTINCT count(*) FROM t3 GROUP BY a;
} { } {
0 0 0 {TABLE t3 (~1000000 rows)} 0 0 0 {SCAN TABLE t3 (~1000000 rows)}
0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR GROUP BY}
0 0 0 {USE TEMP B-TREE FOR DISTINCT} 0 0 0 {USE TEMP B-TREE FOR DISTINCT}
} }
@@ -85,22 +86,52 @@ do_execsql_test 2.1 {
CREATE INDEX t2i1 ON t2(x); CREATE INDEX t2i1 ON t2(x);
} }
do_eqp_test 2.2.1 { det 2.2.1 "SELECT DISTINCT min(x), max(x) FROM t1 GROUP BY x ORDER BY 1" {
SELECT DISTINCT min(x), max(x) FROM t1 GROUP BY x ORDER BY 1 0 0 0 {SCAN TABLE t1 (~1000000 rows)}
} {
0 0 0 {TABLE t1 (~1000000 rows)}
0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR GROUP BY}
0 0 0 {USE TEMP B-TREE FOR DISTINCT} 0 0 0 {USE TEMP B-TREE FOR DISTINCT}
0 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}
} }
det 2.2.2 "SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORDER BY 1" {
do_eqp_test 2.2.2 { 0 0 0 {SCAN TABLE t2 BY COVERING INDEX t2i1 (~1000000 rows)}
SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORDER BY 1
} {
0 0 0 {TABLE t2 WITH COVERING INDEX t2i1 (~1000000 rows)}
0 0 0 {USE TEMP B-TREE FOR DISTINCT} 0 0 0 {USE TEMP B-TREE FOR DISTINCT}
0 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}
} }
det 2.2.3 "SELECT DISTINCT * FROM t1" {
0 0 0 {SCAN TABLE t1 (~1000000 rows)}
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
}
det 2.2.4 "SELECT DISTINCT * FROM t1, t2" {
0 0 0 {SCAN TABLE t1 (~1000000 rows)}
0 1 1 {SCAN TABLE t2 (~1000000 rows)}
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
}
det 2.2.5 "SELECT DISTINCT * FROM t1, t2 ORDER BY t1.x" {
0 0 0 {SCAN TABLE t1 (~1000000 rows)}
0 1 1 {SCAN TABLE t2 (~1000000 rows)}
0 0 0 {USE TEMP B-TREE FOR DISTINCT}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}
det 2.2.6 "SELECT DISTINCT t2.x FROM t1, t2 ORDER BY t2.x" {
0 0 1 {SCAN TABLE t2 BY COVERING INDEX t2i1 (~1000000 rows)}
0 1 0 {SCAN TABLE t1 (~1000000 rows)}
}
det 2.3.1 "SELECT max(x) FROM t2" {
0 0 0 {SCAN TABLE t2 BY COVERING INDEX t2i1 (~1 rows)}
}
det 2.3.2 "SELECT min(x) FROM t2" {
0 0 0 {SCAN TABLE t2 BY COVERING INDEX t2i1 (~1 rows)}
}
det 2.3.3 "SELECT min(x), max(x) FROM t2" {
0 0 0 {SCAN TABLE t2 (~1000000 rows)}
}
det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" {
0 0 0 {SCAN TABLE t1 BY INTEGER PRIMARY KEY (rowid=?) (~1 rows)}
}
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# Test cases eqp-3.* - tests for select statements that use sub-selects. # Test cases eqp-3.* - tests for select statements that use sub-selects.
@@ -108,86 +139,135 @@ do_eqp_test 2.2.2 {
do_eqp_test 3.1.1 { do_eqp_test 3.1.1 {
SELECT (SELECT x FROM t1 AS sub) FROM t1; SELECT (SELECT x FROM t1 AS sub) FROM t1;
} { } {
0 0 0 {TABLE t1 (~1000000 rows)} 0 0 0 {SCAN TABLE t1 (~1000000 rows)}
1 0 0 {TABLE t1 AS sub (~1000000 rows)} 0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t1 AS sub (~1000000 rows)}
}
do_eqp_test 3.1.2 {
SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub);
} {
0 0 0 {SCAN TABLE t1 (~1000000 rows)}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t1 AS sub (~1000000 rows)}
}
do_eqp_test 3.1.3 {
SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y);
} {
0 0 0 {SCAN TABLE t1 (~1000000 rows)}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t1 AS sub (~1000000 rows)}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
}
do_eqp_test 3.1.4 {
SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x);
} {
0 0 0 {SCAN TABLE t1 (~1000000 rows)}
0 0 0 {EXECUTE SCALAR SUBQUERY 1}
1 0 0 {SCAN TABLE t2 BY COVERING INDEX t2i1 (~1000000 rows)}
}
det 3.2.1 {
SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5
} {
1 0 0 {SCAN TABLE t1 (~1000000 rows)}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
0 0 0 {SCAN SUBQUERY 1 (~1000000 rows)}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}
det 3.2.2 {
SELECT * FROM
(SELECT * FROM t1 ORDER BY x LIMIT 10) AS x1,
(SELECT * FROM t2 ORDER BY x LIMIT 10) AS x2
ORDER BY x2.y LIMIT 5
} {
1 0 0 {SCAN TABLE t1 (~1000000 rows)}
1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {SCAN TABLE t2 BY INDEX t2i1 (~1000000 rows)}
0 0 0 {SCAN SUBQUERY 1 AS x1 (~1000000 rows)}
0 1 1 {SCAN SUBQUERY 2 AS x2 (~1000000 rows)}
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
} }
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# Test cases eqp-4.* - tests for select statements that use sub-selects. # Test cases eqp-4.* - tests for composite select statements.
# #
do_eqp_test 4.1.1 { do_eqp_test 4.1.1 {
SELECT * FROM t1 UNION ALL SELECT * FROM t2 SELECT * FROM t1 UNION ALL SELECT * FROM t2
} { } {
1 0 0 {TABLE t1 (~1000000 rows)} 1 0 0 {SCAN TABLE t1 (~1000000 rows)}
2 0 0 {TABLE t2 (~1000000 rows)} 2 0 0 {SCAN TABLE t2 (~1000000 rows)}
} }
do_eqp_test 4.1.2 { do_eqp_test 4.1.2 {
SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 2 SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 2
} { } {
1 0 0 {TABLE t1 (~1000000 rows)} 1 0 0 {SCAN TABLE t1 (~1000000 rows)}
1 0 0 {USE TEMP B-TREE FOR ORDER BY} 1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {TABLE t2 (~1000000 rows)} 2 0 0 {SCAN TABLE t2 (~1000000 rows)}
2 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {USE TEMP B-TREE FOR ORDER BY}
} }
do_eqp_test 4.1.3 { do_eqp_test 4.1.3 {
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 2 SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 2
} { } {
1 0 0 {TABLE t1 (~1000000 rows)} 1 0 0 {SCAN TABLE t1 (~1000000 rows)}
1 0 0 {USE TEMP B-TREE FOR ORDER BY} 1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {TABLE t2 (~1000000 rows)} 2 0 0 {SCAN TABLE t2 (~1000000 rows)}
2 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {USE TEMP B-TREE FOR ORDER BY}
} }
do_eqp_test 4.1.4 { do_eqp_test 4.1.4 {
SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 2 SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 2
} { } {
1 0 0 {TABLE t1 (~1000000 rows)} 1 0 0 {SCAN TABLE t1 (~1000000 rows)}
1 0 0 {USE TEMP B-TREE FOR ORDER BY} 1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {TABLE t2 (~1000000 rows)} 2 0 0 {SCAN TABLE t2 (~1000000 rows)}
2 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {USE TEMP B-TREE FOR ORDER BY}
} }
do_eqp_test 4.1.5 { do_eqp_test 4.1.5 {
SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 2 SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 2
} { } {
1 0 0 {TABLE t1 (~1000000 rows)} 1 0 0 {SCAN TABLE t1 (~1000000 rows)}
1 0 0 {USE TEMP B-TREE FOR ORDER BY} 1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {TABLE t2 (~1000000 rows)} 2 0 0 {SCAN TABLE t2 (~1000000 rows)}
2 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {USE TEMP B-TREE FOR ORDER BY}
} }
do_eqp_test 4.2.2 { do_eqp_test 4.2.2 {
SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 1 SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 1
} { } {
1 0 0 {TABLE t1 (~1000000 rows)} 1 0 0 {SCAN TABLE t1 (~1000000 rows)}
1 0 0 {USE TEMP B-TREE FOR ORDER BY} 1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {TABLE t2 WITH INDEX t2i1 (~1000000 rows)} 2 0 0 {SCAN TABLE t2 BY INDEX t2i1 (~1000000 rows)}
} }
# Todo: Why are the following not the same as the UNION ALL case above?
do_eqp_test 4.2.3 { do_eqp_test 4.2.3 {
SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 1 SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 1
} { } {
1 0 0 {TABLE t1 (~1000000 rows)} 1 0 0 {SCAN TABLE t1 (~1000000 rows)}
1 0 0 {USE TEMP B-TREE FOR ORDER BY} 1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {TABLE t2 (~1000000 rows)} 2 0 0 {SCAN TABLE t2 (~1000000 rows)}
2 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {USE TEMP B-TREE FOR ORDER BY}
} }
do_eqp_test 4.2.4 { do_eqp_test 4.2.4 {
SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 1 SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 1
} { } {
1 0 0 {TABLE t1 (~1000000 rows)} 1 0 0 {SCAN TABLE t1 (~1000000 rows)}
1 0 0 {USE TEMP B-TREE FOR ORDER BY} 1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {TABLE t2 (~1000000 rows)} 2 0 0 {SCAN TABLE t2 (~1000000 rows)}
2 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {USE TEMP B-TREE FOR ORDER BY}
} }
do_eqp_test 4.2.5 { do_eqp_test 4.2.5 {
SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 1 SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 1
} { } {
1 0 0 {TABLE t1 (~1000000 rows)} 1 0 0 {SCAN TABLE t1 (~1000000 rows)}
1 0 0 {USE TEMP B-TREE FOR ORDER BY} 1 0 0 {USE TEMP B-TREE FOR ORDER BY}
2 0 0 {TABLE t2 (~1000000 rows)} 2 0 0 {SCAN TABLE t2 (~1000000 rows)}
2 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {USE TEMP B-TREE FOR ORDER BY}
} }
do_eqp_test 4.3.1 {
SELECT x FROM t1 UNION SELECT x FROM t2
} {
1 0 0 {SCAN TABLE t1 (~1000000 rows)}
2 0 0 {SCAN TABLE t2 (~1000000 rows)}
}
finish_test finish_test