]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
If the outer loop of a join must be a full table scan, make sure that an
authordrh <drh@noemail.net>
Wed, 4 Aug 2010 21:17:16 +0000 (21:17 +0000)
committerdrh <drh@noemail.net>
Wed, 4 Aug 2010 21:17:16 +0000 (21:17 +0000)
incomplete ANALYZE does not trick the planner into use a table that might
be indexable in an inner loop.  Ticket [13f033c865f878]

FossilOrigin-Name: e7a714b52c45af096af74049826d32c647abfe3f

manifest
manifest.uuid
src/where.c
test/indexedby.test
test/where3.test

index 7f3d514ca1ec23e6a35286200e5cf9dca6dfe72d..1e36899f17416b3b8a190432d31fbaae67367067 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,8 @@
-C When\sopening\sa\swrite-transaction\son\sa\sdatabase\sfile\sthat\shas\sbeen\sappended\sto\sor\struncated\sby\sa\spre-3.7.0\sclient,\supdate\sthe\sdatabase-size\sfield\sin\sthe\sdatabase\sheader.\sFix\sfor\s[51ae9cad31].
-D 2010-08-04T11:34:31
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+C If\sthe\souter\sloop\sof\sa\sjoin\smust\sbe\sa\sfull\stable\sscan,\smake\ssure\sthat\san\nincomplete\sANALYZE\sdoes\snot\strick\sthe\splanner\sinto\suse\sa\stable\sthat\smight\nbe\sindexable\sin\san\sinner\sloop.\s\sTicket\s[13f033c865f878]
+D 2010-08-04T21:17:16
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in ec08dc838fd8110fe24c92e5130bcd91cbb1ff2e
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -230,7 +233,7 @@ F src/vtab.c 82200af3881fa4e1c9cf07cf31d98c09d437e3ab
 F src/wal.c 0925601f3299c2941a67c9cfff41ee710f70ca82
 F src/wal.h 906c85760598b18584921fe08008435aa4eeeeb2
 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
-F src/where.c 79202ca81e740eeb1f54512147e29b6c518d84ca
+F src/where.c a1398b29b8ec129ab656ee136e9116fc2f26e3f2
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
 F test/all.test 6745008c144bd2956d58864d21f7b304689c1cce
@@ -445,7 +448,7 @@ F test/incrvacuum_ioerr.test 57d2f5777ab13fa03b87b262a4ea1bad5cfc0291
 F test/index.test cbf301cdb2da43e4eac636c3400c2439af1834ad
 F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
 F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
-F test/indexedby.test 946ca2628a521f4ced0520421a0788345abaf3dc
+F test/indexedby.test 5a1180602f2e72c481467bd4cae05dae5dc36f47
 F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
 F test/insert.test aef273dd1cee84cc92407469e6bd1b3cdcb76908
 F test/insert2.test 4f3a04d168c728ed5ec2c88842e772606c7ce435
@@ -798,7 +801,7 @@ F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
 F test/walthread.test a25a393c068a2b42b44333fa3fdaae9072f1617c
 F test/where.test de337a3fe0a459ec7c93db16a519657a90552330
 F test/where2.test 43d4becaf5a5df854e6c21d624a1cb84c6904554
-F test/where3.test aa44a9b29e8c9f3d7bb94a3bb3a95b31627d520d
+F test/where3.test acdacc5e1e50ea935b74b3378e4e4b3fa4950092
 F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
@@ -841,7 +844,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 57c0960038b8ce97f9d6665f15e7f6ec310c681f
-R 2302fd10d4e5885f2536eafbb69bad6e
-U dan
-Z a94bacf2e85499d72182ad0845d48def
+P 65b8636ac6e5d3e4502d4f576ddf9350d5df3022
+R f303f8cd6c15f9355d52ea6f34dbc596
+U drh
+Z 334acc501b61b4dedf959e66e446e709
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.6 (GNU/Linux)
+
+iD8DBQFMWdjfoxKgR168RlERAtzHAJsHfo8i9JQtGPiUDENko/1YB6PzvwCfchpH
+IJ8P1uaP+Eu9M19yQeVqg/o=
+=L8a0
+-----END PGP SIGNATURE-----
index 6b50305f08569f4ab93b85909ac392e4bbb28739..4af956306e86321b907300fab2e40fdaf3b0a5e7 100644 (file)
@@ -1 +1 @@
-65b8636ac6e5d3e4502d4f576ddf9350d5df3022
\ No newline at end of file
+e7a714b52c45af096af74049826d32c647abfe3f
\ No newline at end of file
index e527fbd6f4e5f222e4323690e5ddbc3e91a4a106..d32997d063c343dfd2d8a74cb4bee4faabb372ff 100644 (file)
@@ -4064,6 +4064,7 @@ WhereInfo *sqlite3WhereBegin(
     int bestJ = -1;             /* The value of j */
     Bitmask m;                  /* Bitmask value for j or bestJ */
     int isOptimal;              /* Iterator for optimal/non-optimal search */
+    int nUnconstrained;         /* Number tables without INDEXED BY */
 
     memset(&bestPlan, 0, sizeof(bestPlan));
     bestPlan.rCost = SQLITE_BIG_DBL;
@@ -4105,6 +4106,7 @@ WhereInfo *sqlite3WhereBegin(
     ** algorithm may choose to use t2 for the outer loop, which is a much
     ** costlier approach.
     */
+    nUnconstrained = 0;
     for(isOptimal=(iFrom<nTabList-1); isOptimal>=0; isOptimal--){
       Bitmask mask;  /* Mask of tables not yet ready */
       for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
@@ -4121,6 +4123,7 @@ WhereInfo *sqlite3WhereBegin(
         }
         mask = (isOptimal ? m : notReady);
         pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
+        if( pTabItem->pIndex==0 ) nUnconstrained++;
   
         assert( pTabItem->pTab );
 #ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -4134,9 +4137,28 @@ WhereInfo *sqlite3WhereBegin(
         }
         assert( isOptimal || (sCost.used&notReady)==0 );
 
-        if( (sCost.used&notReady)==0
-         && (bestJ<0 || sCost.rCost<bestPlan.rCost
-             || (sCost.rCost<=bestPlan.rCost && sCost.nRow<bestPlan.nRow))
+        /* Conditions under which this table becomes the best so far:
+        **
+        **   (1) The table must not depend on other tables that have not
+        **       yet run.
+        **
+        **   (2) A full-table-scan plan cannot supercede another plan unless
+        **       the full-table-scan is an optimal plan.
+        **
+        **   (3) The plan cost must be lower than prior plans or else the
+        **       cost must be the same and the number of rows must be lower.
+        **
+        **   (4) All tables have an INDEXED BY clause or this table lacks an
+        **       INDEXED BY clause or this table uses the specific
+        **       index specified by its INDEXED BY clause.
+        */
+        if( (sCost.used&notReady)==0                       /* (1) */
+            && (bestJ<0 || isOptimal                       /* (2) */
+                || (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
+            && (bestJ<0 || sCost.rCost<bestPlan.rCost      /* (3) */
+                || (sCost.rCost<=bestPlan.rCost && sCost.nRow<bestPlan.nRow))
+            && (nUnconstrained==0 || pTabItem->pIndex==0   /* (4) */
+                || pTabItem->pIndex==sCost.plan.u.pIdx)
         ){
           WHERETRACE(("... best so far with cost=%g and nRow=%g\n",
                       sCost.rCost, sCost.nRow));
index 62a2a5fd43413f856dc8e12a219da0200e218bd8..70ab9f9b21eb0b80b20541e7ceacd26cd9ee1182 100644 (file)
@@ -123,6 +123,16 @@ do_test indexedby-4.1 {
 do_test indexedby-4.2 {
   EQP { SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c }
 } {0 1 {TABLE t2} 1 0 {TABLE t1 WITH INDEX i1}}
+do_test indexedby-4.3 {
+  catchsql {
+    SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c
+  }
+} {1 {cannot use index: i1}}
+do_test indexedby-4.4 {
+  catchsql {
+    SELECT * FROM t2 INDEXED BY i3, t1 INDEXED BY i1 WHERE a=c
+  }
+} {1 {cannot use index: i3}}
 
 # Test embedding an INDEXED BY in a CREATE VIEW statement. This block
 # also tests that nothing bad happens if an index refered to by
index 13f947329db50226d629c495a10afd8a2530f746..7296e6a68918a709877cc8416ab43a6ddb153524 100644 (file)
@@ -212,5 +212,27 @@ do_test where3-2.7 {
   }
 } {tB {} tC * tA * tD *}
 
+# Ticket [13f033c865f878953]
+# If the outer loop must be a full table scan, do not let ANALYZE trick
+# the planner into use a table for the outer loop that might be indexable
+# if held until an inner loop.
+# 
+do_test where3-3.0 {
+  execsql {
+    CREATE TABLE t301(a INTEGER PRIMARY KEY,b,c);
+    CREATE INDEX t301c ON t301(c);
+    INSERT INTO t301 VALUES(1,2,3);
+    CREATE TABLE t302(x, y);
+    ANALYZE;
+    explain query plan
+    SELECT * FROM t302, t301 WHERE t302.x=5 AND t301.a=t302.y;
+  }
+} {0 0 {TABLE t302} 1 1 {TABLE t301 USING PRIMARY KEY}}
+do_test where3-3.1 {
+  execsql {
+    explain query plan
+    SELECT * FROM t301, t302 WHERE t302.x=5 AND t301.a=t302.y;
+  }
+} {0 1 {TABLE t302} 1 0 {TABLE t301 USING PRIMARY KEY}}
 
 finish_test