From: drh Date: Fri, 9 Nov 2012 17:59:26 +0000 (+0000) Subject: Try to take into account the cost of inner loops when selecting which table X-Git-Tag: version-3.7.15~41^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=782d68a4cdc0e089899855e228e3dd78a02724e3;p=thirdparty%2Fsqlite.git Try to take into account the cost of inner loops when selecting which table of a join to use for the outer loop. FossilOrigin-Name: 942556342a332b04a11169bb04f387d741ef9488 --- diff --git a/manifest b/manifest index 46d197a9d4..65706de517 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Adjust\sthe\sSQLITE_DBSTATUS_STMT_USED\scalculation\sto\stake\sthe\smodified\susage\sof\ssqlite3VdbeClearObject()\sinto\saccount. -D 2012-11-06T20:39:11.759 +C Try\sto\stake\sinto\saccount\sthe\scost\sof\sinner\sloops\swhen\sselecting\swhich\stable\nof\sa\sjoin\sto\suse\sfor\sthe\souter\sloop. +D 2012-11-09T17:59:26.161 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -179,7 +179,7 @@ F src/shell.c 24cd0aa74aff73ea08594629faead564c4c2a286 F src/sqlite.h.in c7be05ad191d2634292fcc77bdb2bcfa4526eb98 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 -F src/sqliteInt.h f29ed6fbbf80a6d9ac8aae9998ecae2b8d72e0ae +F src/sqliteInt.h 79c00e24d84541c3117ef34ce09c5749dcdcba25 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -249,7 +249,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b -F src/where.c 6a753aa008de6494e64dd265a27afbb0ad80ccf5 +F src/where.c b97f14d4ce618ceb18138238b1bd028cf02014b4 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -636,7 +636,7 @@ F test/notify3.test a86259abbfb923aa27d30f0fc038c88e5251488a F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347 F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 -F test/orderby1.test ef4f7c40df81b9a4303a718433d34052f07db47d +F test/orderby1.test f33968647da5c546528fe4d2bf86c6a6a2e5a7ae F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04 F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3 F test/pager1.test 07116f72a61960b882952e7472cc2846d161d6e2 @@ -974,6 +974,8 @@ F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5 F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5 F test/whereD.test 3f3ee93825c94804f1fc91eef2de0d365981759a +F test/whereE.test 7bd34945797efef15819368479bacc34215e4e1d +F test/whereF.test a0e296643cabe5278379bc1a0aa158cf3c54a1c9 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 @@ -1022,7 +1024,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 6b4979e86c05f2da2c5fff67ea7feec5fa56756a -R 275b30fd4dabbb76a3c510773e928640 -U mistachkin -Z 07851b8d86e7907c3dc0dd17f564d79e +P 82eb7eadb8c76b3af8c811d791f87a634c35935f +R 6e69028f10fbf48578845dd76c89b910 +T *branch * inner-loop-cost +T *sym-inner-loop-cost * +T -sym-trunk * +U drh +Z 386f6fc4840a28b57311013bb9458533 diff --git a/manifest.uuid b/manifest.uuid index 8c413f9a8d..85eae6eacd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -82eb7eadb8c76b3af8c811d791f87a634c35935f \ No newline at end of file +942556342a332b04a11169bb04f387d741ef9488 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e44ce7b7e8..eb779253c9 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1967,6 +1967,7 @@ struct WhereLevel { } in; /* Used when plan.wsFlags&WHERE_IN_ABLE */ Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ } u; + double rOptCost; /* "Optimal" cost for this level */ /* The following field is really not part of the current level. But ** we need a place to cache virtual table index information for each diff --git a/src/where.c b/src/where.c index 38f6f1436f..5fa40994fe 100644 --- a/src/where.c +++ b/src/where.c @@ -4744,6 +4744,16 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ } } +/* +** Return TRUE if the wsFlags indicate that a full table scan (or a +** full scan of a covering index) is indicated. +*/ +static int isFullscan(unsigned wsFlags){ + if( wsFlags & WHERE_COVER_SCAN ) return 1; + if( (wsFlags & WHERE_NOT_FULLSCAN)==0 ) return 1; + return 0; +} + /* ** Generate the beginning of the loop used for WHERE clause processing. @@ -5102,6 +5112,19 @@ WhereInfo *sqlite3WhereBegin( if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){ notIndexed |= m; } + if( isOptimal ){ + pWInfo->a[j].rOptCost = sWBI.cost.rCost; + }else if( iFroma[j].rOptCost)); + sWBI.cost.rCost /= pWInfo->a[j].rOptCost; + } /* Conditions under which this table becomes the best so far: ** @@ -5126,8 +5149,8 @@ WhereInfo *sqlite3WhereBegin( */ if( (sWBI.cost.used&sWBI.notValid)==0 /* (1) */ && (bestJ<0 || (notIndexed&m)!=0 /* (2) */ - || (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 - || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0) + || isFullscan(bestPlan.plan.wsFlags) + || !isFullscan(sWBI.cost.plan.wsFlags)) && (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */ || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)) && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */ diff --git a/test/orderby1.test b/test/orderby1.test index 2001e34009..f459fc8195 100644 --- a/test/orderby1.test +++ b/test/orderby1.test @@ -48,7 +48,7 @@ do_test 1.0 { } {} do_test 1.1a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} @@ -57,7 +57,7 @@ do_test 1.1a { do_test 1.1b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {~/ORDER BY/} ;# ORDER BY optimized out @@ -66,7 +66,7 @@ do_test 1.1b { # do_test 1.2a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn } } {one-a one-c two-a two-b three-a three-c} @@ -75,7 +75,7 @@ do_test 1.2a { do_test 1.2b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn } } {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms @@ -85,13 +85,13 @@ do_test 1.3a { optimization_control db order-by-idx-join 0 db cache flush db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} do_test 1.3b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {/ORDER BY/} ;# separate sorting pass due to disabled optimization optimization_control db all 1 @@ -101,53 +101,53 @@ db cache flush # do_test 1.4a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn } } {three-a three-c two-a two-b one-a one-c} do_test 1.4b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn } } {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting do_test 1.4c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn } } {~/ORDER BY/} ;# optimized out do_test 1.5a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} do_test 1.5b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC } } {one-c one-a two-b two-a three-c three-a} ;# verify same order after sorting do_test 1.5c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {~/ORDER BY/} ;# optimized out do_test 1.6a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {three-c three-a two-b two-a one-c one-a} do_test 1.6b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC } } {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting do_test 1.6c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {~/ORDER BY/} ;# ORDER BY optimized-out @@ -183,7 +183,7 @@ do_test 2.0 { } {} do_test 2.1a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} @@ -192,19 +192,19 @@ do_test 2.1a { do_test 2.1b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {~/ORDER BY/} ;# ORDER BY optimized out do_test 2.1c { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, aid, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, aid, tn } } {one-a one-c two-a two-b three-a three-c} do_test 2.1d { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, aid, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, aid, tn } } {~/ORDER BY/} ;# ORDER BY optimized out @@ -213,7 +213,7 @@ do_test 2.1d { # do_test 2.2a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn } } {one-a one-c two-a two-b three-a three-c} @@ -222,7 +222,7 @@ do_test 2.2a { do_test 2.2b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn } } {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms @@ -232,13 +232,13 @@ do_test 2.3a { optimization_control db order-by-idx-join 0 db cache flush db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} do_test 2.3b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {/ORDER BY/} ;# separate sorting pass due to disabled optimization optimization_control db all 1 @@ -248,53 +248,53 @@ db cache flush # do_test 2.4a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn } } {three-a three-c two-a two-b one-a one-c} do_test 2.4b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn } } {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting do_test 2.4c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn } } {~/ORDER BY/} ;# optimized out do_test 2.5a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} do_test 2.5b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC } } {one-c one-a two-b two-a three-c three-a} ;# verify same order after sorting do_test 2.5c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {~/ORDER BY/} ;# optimized out do_test 2.6a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {three-c three-a two-b two-a one-c one-a} do_test 2.6b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC } } {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting do_test 2.6c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {~/ORDER BY/} ;# ORDER BY optimized out @@ -330,7 +330,7 @@ do_test 3.0 { } {} do_test 3.1a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} @@ -339,7 +339,7 @@ do_test 3.1a { do_test 3.1b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {~/ORDER BY/} ;# ORDER BY optimized out @@ -348,7 +348,7 @@ do_test 3.1b { # do_test 3.2a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC } } {one-c one-a two-b two-a three-c three-a} @@ -357,7 +357,7 @@ do_test 3.2a { do_test 3.2b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC } } {/ORDER BY/} ;# separate sorting pass due to "+" on ORDER BY terms @@ -367,13 +367,13 @@ do_test 3.3a { optimization_control db order-by-idx-join 0 db cache flush db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {one-c one-a two-b two-a three-c three-a} do_test 3.3b { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC } } {/ORDER BY/} ;# separate sorting pass due to disabled optimization optimization_control db all 1 @@ -383,54 +383,54 @@ db cache flush # do_test 3.4a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {one-a one-c two-a two-b three-a three-c} do_test 3.4b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn } } {one-a one-c two-a two-b three-a three-c} ;# verify same order after sorting do_test 3.4c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn } } {~/ORDER BY/} ;# optimized out do_test 3.5a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {three-c three-a two-b two-a one-c one-a} do_test 3.5b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC } } {three-c three-a two-b two-a one-c one-a} ;# verify same order after sorting do_test 3.5c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC } } {~/ORDER BY/} ;# optimzed out do_test 3.6a { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn } } {three-a three-c two-a two-b one-a one-c} do_test 3.6b { db eval { - SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn } } {three-a three-c two-a two-b one-a one-c} ;# verify same order after sorting do_test 3.6c { db eval { EXPLAIN QUERY PLAN - SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn + SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn } } {~/ORDER BY/} ;# inverted ASC/DESC is optimized out diff --git a/test/whereE.test b/test/whereE.test new file mode 100644 index 0000000000..e686a4628e --- /dev/null +++ b/test/whereE.test @@ -0,0 +1,62 @@ +# 2012 November 9 +# +# 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 regression tests for SQLite library. The +# focus of this file is testing the query planner to make sure it +# is making good planning decisions. +# + + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix whereE + +do_execsql_test 1.1 { + CREATE TABLE t1(a,b); + INSERT INTO t1 VALUES(1,10), (2,20), (3,30), (2,22), (3, 33); + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + INSERT INTO t1 SELECT * FROM t1; + ALTER TABLE t1 ADD COLUMN c; + UPDATE t1 SET c=a*rowid+10000; + CREATE INDEX t1ab ON t1(a,b); + + CREATE TABLE t2(x,y); + INSERT INTO t2 VALUES(4,44),(5,55),(6,66),(7,77); + INSERT INTO t2 SELECT x+4, (x+4)*11 FROM t2; + INSERT INTO t2 SELECT x+8, (x+8)*11 FROM t2; + INSERT INTO t2 SELECT x+16, (x+16)*11 FROM t2; + INSERT INTO t2 SELECT x+32, (x+32)*11 FROM t2; + INSERT INTO t2 SELECT x+64, (x+32)*11 FROM t2; + ALTER TABLE t2 ADD COLUMN z; + UPDATE t2 SET z=2; + CREATE UNIQUE INDEX t2zx ON t2(z,x); + + EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; +} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +do_execsql_test 1.2 { + EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; +} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +do_execsql_test 1.3 { + ANALYZE; + EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x; +} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} +do_execsql_test 1.4 { + EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x; +} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/} + +finish_test diff --git a/test/whereF.test b/test/whereF.test new file mode 100644 index 0000000000..57bdbee058 --- /dev/null +++ b/test/whereF.test @@ -0,0 +1,115 @@ +# 2012 November 9 +# +# 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. +# +#*********************************************************************** +# +# Test cases for query planning decisions. + + +# +# The tests in this file demonstrate the behaviour of the query planner +# in determining the order in which joined tables are scanned. +# +# Assume there are two tables being joined - t1 and t2. Each has a cost +# if it is the outer loop, and a cost if it is the inner loop. As follows: +# +# t1(outer) - cost of scanning t1 as the outer loop. +# t1(inner) - cost of scanning t1 as the inner loop. +# t2(outer) - cost of scanning t2 as the outer loop. +# t2(inner) - cost of scanning t2 as the inner loop. +# +# Depending on the order in which the planner nests the scans, the total +# cost of the join query is one of: +# +# t1(outer) * t2(inner) +# t2(outer) * t1(inner) +# +# The tests in this file attempt to verify that the planner nests joins in +# the correct order when the following are true: +# +# + (t1(outer) * t2(inner)) > (t1(inner) * t2(outer) +# + t1(outer) < t2(outer) +# +# In other words, when the best overall query plan has t2 as the outer loop, +# but when the outer loop is considered independent of the inner, t1 is the +# most efficient choice. +# +# In order to make them more predictable, automatic indexes are turned off for +# the tests in this file. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix x + +do_execsql_test 1.0 { + PRAGMA automatic_index = 0; + CREATE TABLE t1(a, b, c); + CREATE TABLE t2(d, e, f); + CREATE UNIQUE INDEX i1 ON t1(a); + CREATE UNIQUE INDEX i2 ON t2(d); +} {} + +foreach {tn sql} { + 1 "SELECT * FROM t1, t2 WHERE t1.a=t2.e AND t2.d? AND t2.d>t1.c AND t1.b=t2.e" + 2 "SELECT * FROM t2, t1 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e" + 3 "SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e" +} { + do_test 2.$tn { + db eval "EXPLAIN QUERY PLAN $sql" + } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/} +} + +do_execsql_test 3.0 { + DROP TABLE t1; + DROP TABLE t2; + CREATE TABLE t1(a, b, c); + CREATE TABLE t2(d, e, f); + + CREATE UNIQUE INDEX i1 ON t1(a, b); + CREATE INDEX i2 ON t2(d); +} {} + +foreach {tn sql} { + 1 {SELECT t1.a, t1.b, t2.d, t2.e FROM t1, t2 + WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)} + + 2 {SELECT t1.a, t1.b, t2.d, t2.e FROM t2, t1 + WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)} + + 3 {SELECT t1.a, t1.b, t2.d, t2.e FROM t2 CROSS JOIN t1 + WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)} +} { + do_test 3.$tn { + db eval "EXPLAIN QUERY PLAN $sql" + } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/} +} + +finish_test