Index: src/where.c ================================================================== --- src/where.c +++ src/where.c @@ -2040,10 +2040,33 @@ && p->rRun<=pTemplate->rRun /* (2b) */ && p->nOut<=pTemplate->nOut /* (2c) */ ){ return 0; /* Discard pTemplate */ } + + /* If pTemplate: + ** + ** (1) uses the same index as existing where-loop p, + ** (2) requires the same or a superset of tables to be scanned first, + ** (3) constraints the same or fewer columns with ==, and + ** (4) skips more leading columns (skip-scan optimization). + ** + ** the discard the template. This ensures that if stat4 data shows that: + ** + ** WHERE (a=1 AND b=2) + ** + ** is prohibitively expensive the planner does not instead do: + ** + ** WHERE (ANY(a) AND b=2) + */ + if( pTemplate->nSkip>p->nSkip /* (4) */ + && pTemplate->u.btree.pIndex==p->u.btree.pIndex /* (1) */ + && pTemplate->u.btree.nEq<=p->u.btree.nEq /* (3) */ + && (pTemplate->prereq & p->prereq)==p->prereq /* (2) */ + ){ + return 0; /* Discard pTemplate */ + } /* If pTemplate is always better than p, then cause p to be overwritten ** with pTemplate. pTemplate is better than p if: ** (1) pTemplate has no more dependences than p, and ** (2) pTemplate has an equal or lower cost than p. ADDED test/analyzeG.test Index: test/analyzeG.test ================================================================== --- /dev/null +++ test/analyzeG.test @@ -0,0 +1,54 @@ +# 2018-07-04 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix analyzeG + +ifcapable {!stat4} { + finish_test + return +} + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b, c, d); + CREATE INDEX t1abc ON t1(a, b, c); + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100000 + ) + INSERT INTO t1 SELECT 1,1,1,1 FROM s; + + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1000 + ) + INSERT INTO t1 SELECT i%5,i,i,i FROM s; +} + +do_execsql_test 1.1 { + EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 AND b=1 AND c>0 +} { + 3 0 0 {SEARCH TABLE t1 USING INDEX t1abc (a=? AND b=? AND c>?)} +} + +do_execsql_test 1.3 { + ANALYZE +} {} + +do_execsql_test 1.4 { + EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 AND b=1 AND c>0 +} { + 2 0 0 {SCAN TABLE t1} +} + + + +finish_test