If the outer loop of a join must be a full table scan, make sure that an
incomplete ANALYZE does not trick the planner into use a table that might be indexable in an inner loop. Ticket [13f033c865f878] FossilOrigin-Name: e7a714b52c45af096af74049826d32c647abfe3f
This commit is contained in:
parent
59257dc615
commit
5e377d90ed
28
manifest
28
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-----
|
||||
|
@ -1 +1 @@
|
||||
65b8636ac6e5d3e4502d4f576ddf9350d5df3022
|
||||
e7a714b52c45af096af74049826d32c647abfe3f
|
26
src/where.c
26
src/where.c
@ -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¬Ready)==0 );
|
||||
|
||||
if( (sCost.used¬Ready)==0
|
||||
&& (bestJ<0 || sCost.rCost<bestPlan.rCost
|
||||
/* 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¬Ready)==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));
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user