From: dan Date: Wed, 4 Jul 2018 14:28:07 +0000 (+0000) Subject: Experimental planner change to avoid a skip-scan if a regular index scan on X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fexp-avoid-expensive-skipscan;p=thirdparty%2Fsqlite.git Experimental planner change to avoid a skip-scan if a regular index scan on the same index columns can be done instead. FossilOrigin-Name: 32924446db0d07e5b2661a6626136a7bcdda629de23f98f3e1e862dd52d2f8a5 --- diff --git a/manifest b/manifest index 2357a1bfd4..3e7e1ec234 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Test\sthat\sa\srace\scondition\scan\scause\sa\s"BEGIN\sEXCLUSIVE"\sto\sreturn\nSQLITE_BUSY_SNAPSHOT\sin\swal\smode. -D 2018-07-03T20:17:27.649 +C Experimental\splanner\schange\sto\savoid\sa\sskip-scan\sif\sa\sregular\sindex\sscan\son\nthe\ssame\sindex\scolumns\scan\sbe\sdone\sinstead. +D 2018-07-04T14:28:07.015 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6 @@ -580,7 +580,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c d44a0811afd2155b1157c38b33141d4ac028fda6232485bed664015bb05819ca F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4 -F src/where.c 0bcbf9e191ca07f9ea2008aa80e70ded46bcdffd26560c83397da501f00aece6 +F src/where.c a38a485f36335c299f1810bcba11fa3cfe7ac10bc6148e4c13500a9c79d59219 F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4 F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96 F src/whereexpr.c 571618c67a3eb5ce0f1158c2792c1aee9b4a4a264392fc4fb1b35467f80abf9a @@ -612,6 +612,7 @@ F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93 F test/analyzeD.test e50cd0b3e6063216cc0c88a1776e8645dc0bd65a6bb275769cbee33b7fd8d90c F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d F test/analyzeF.test 9e1a0537949eb5483642b1140a5c39e5b4025939024b935398471fa552f4dabb +F test/analyzeG.test 266499f54bb42a56382ac5c8d2efafe7a0d52290395c5bc5b4a1f5254569132f F test/analyzer1.test 459fa02c445ddbf0101a3bad47b34290a35f2e49 F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b @@ -1745,7 +1746,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P b6563647382634588ebe5c6a3c35c65a321dc1b3732c809d48ce46759b9dd80f -R 85d71bbec8ad4dcf2f8e9507c907b291 +P 5a12db75d1da65daa92413a6b5892309e9d9479bb3610764e1015abe5bf28dbe +R d1c973cef7dd338d2474c5f688523a12 +T *branch * exp-avoid-expensive-skipscan +T *sym-exp-avoid-expensive-skipscan * +T -sym-trunk * U dan -Z 38cb85199c9d8fc14bf46fba2bfb3f49 +Z 68eb1d8d6b0bd6cc041bab15b5fea3f0 diff --git a/manifest.uuid b/manifest.uuid index e6f611aeb3..98e9a2b0fc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5a12db75d1da65daa92413a6b5892309e9d9479bb3610764e1015abe5bf28dbe \ No newline at end of file +32924446db0d07e5b2661a6626136a7bcdda629de23f98f3e1e862dd52d2f8a5 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 7d53715923..bdeaa5fe8d 100644 --- a/src/where.c +++ b/src/where.c @@ -2043,6 +2043,29 @@ static WhereLoop **whereLoopFindLesser( 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 diff --git a/test/analyzeG.test b/test/analyzeG.test new file mode 100644 index 0000000000..ba45004b3a --- /dev/null +++ b/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