]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix the STAT4 range scan estimates for DESC indexes.
authordrh <drh@noemail.net>
Wed, 8 Oct 2014 02:53:25 +0000 (02:53 +0000)
committerdrh <drh@noemail.net>
Wed, 8 Oct 2014 02:53:25 +0000 (02:53 +0000)
FossilOrigin-Name: e3fe84005259ef9a6027d25793514cebb2d4e7e0

manifest
manifest.uuid
src/where.c
test/analyzeE.test [new file with mode: 0644]

index 7b23da26a84bdc915d742184a59e275c7b021d42..36cf57e18dcdc4af418c0c6dc347d3f31f1c9aba 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C More\sintuitive\slabels\son\s".wheretrace"\soutput.
-D 2014-10-08T00:08:08.905
+C Fix\sthe\sSTAT4\srange\sscan\sestimates\sfor\sDESC\sindexes.
+D 2014-10-08T02:53:25.568
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -302,7 +302,7 @@ F src/vtab.c 019dbfd0406a7447c990e1f7bd1dfcdb8895697f
 F src/wal.c 10e7de7ce90865a68153f001a61f1d985cd17983
 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
-F src/where.c 74e1f7e136bfb52c9c65a55909f8a24873b1edb5
+F src/where.c 982f1ce21355452f2e5cd284359ab141c1eff547
 F src/whereInt.h 124d970450955a6982e174b07c320ae6d62a595c
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -327,6 +327,7 @@ F test/analyzeA.test 3335697f6700c7052295cfd0067fc5b2aacddf9a
 F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d
 F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93
 F test/analyzeD.test 08f9d0bee4e118a66fff3a32d02dbe0ee0a2b594
+F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d
 F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
 F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
 F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
@@ -1202,7 +1203,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P f672a380e2e52bede95ff11a533fd9f7d412d494
-R b98bb7ee2a60e85b3c67deaa06ee1000
+P adcb3fed489b580221c7bf2692a60e24248b23a0
+R 50f3751b824cfe9cc6f7ad401beb29e1
 U drh
-Z 71a8e8f52b1016a5adbdd28eb6eb38bb
+Z 07946a58b794ebe5e4cb12afd1dbd645
index bfe9547db3b2c9e15d57386e5e20fc3a900226c9..ee71c7f98a1690ecb3c81f38e0c683dc4c6e8cd4 100644 (file)
@@ -1 +1 @@
-adcb3fed489b580221c7bf2692a60e24248b23a0
\ No newline at end of file
+e3fe84005259ef9a6027d25793514cebb2d4e7e0
\ No newline at end of file
index 23481bb05e569c30601e3da023128a20144b422d..236337a40513c33521a8569d972b21a809546971 100644 (file)
@@ -2207,16 +2207,22 @@ static int whereRangeScanEst(
         iUpper = a[0] + a[1];
       }
 
+      assert( pLower==0 || (pLower->eOperator & (WO_GT|WO_GE))!=0 );
+      assert( pUpper==0 || (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
+      if( p->pKeyInfo && p->pKeyInfo->aSortOrder[nEq] ){
+        /* The roles of pLower and pUpper are swapped for a DESC index */
+        SWAP(WhereTerm*, pLower, pUpper);
+      }
+
       /* If possible, improve on the iLower estimate using ($P:$L). */
       if( pLower ){
         int bOk;                    /* True if value is extracted from pExpr */
         Expr *pExpr = pLower->pExpr->pRight;
-        assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
         rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
         if( rc==SQLITE_OK && bOk ){
           tRowcnt iNew;
           whereKeyStats(pParse, p, pRec, 0, a);
-          iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0);
+          iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
           if( iNew>iLower ) iLower = iNew;
           nOut--;
           pLower = 0;
@@ -2227,12 +2233,11 @@ static int whereRangeScanEst(
       if( pUpper ){
         int bOk;                    /* True if value is extracted from pExpr */
         Expr *pExpr = pUpper->pExpr->pRight;
-        assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
         rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
         if( rc==SQLITE_OK && bOk ){
           tRowcnt iNew;
           whereKeyStats(pParse, p, pRec, 1, a);
-          iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0);
+          iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0);
           if( iNew<iUpper ) iUpper = iNew;
           nOut--;
           pUpper = 0;
diff --git a/test/analyzeE.test b/test/analyzeE.test
new file mode 100644 (file)
index 0000000..66db1e1
--- /dev/null
@@ -0,0 +1,242 @@
+# 2014-10-08
+#
+# 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 tests for using STAT4 information
+# on a descending index in a range query.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set ::testprefix analyzeE
+
+ifcapable {!stat4} {
+  finish_test
+  return
+}
+
+# Verify that range queries on an ASCENDING index will use the
+# index only if the range covers only a small fraction of the
+# entries.
+#
+do_execsql_test analyzeE-1.0 {
+  CREATE TABLE t1(a,b);
+  WITH RECURSIVE
+    cnt(x) AS (VALUES(1000) UNION ALL SELECT x+1 FROM cnt WHERE x<2000)
+  INSERT INTO t1(a,b) SELECT x, x FROM cnt;
+  CREATE INDEX t1a ON t1(a);
+  ANALYZE;
+} {}
+do_execsql_test analyzeE-1.1 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500;
+} {/SCAN TABLE t1/}
+do_execsql_test analyzeE-1.2 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000;
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-1.3 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750;
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-1.4 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 1 AND 500
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-1.5 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-1.6 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a<500
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-1.7 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a>2500
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-1.8 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a>1900
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-1.9 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a>1100
+} {/SCAN TABLE t1/}
+do_execsql_test analyzeE-1.10 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a<1100
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-1.11 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a<1900
+} {/SCAN TABLE t1/}
+
+# Verify that everything works the same on a DESCENDING index.
+#
+do_execsql_test analyzeE-2.0 {
+  DROP INDEX t1a;
+  CREATE INDEX t1a ON t1(a DESC);
+  ANALYZE;
+} {}
+do_execsql_test analyzeE-2.1 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500;
+} {/SCAN TABLE t1/}
+do_execsql_test analyzeE-2.2 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000;
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-2.3 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750;
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-2.4 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 1 AND 500
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-2.5 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-2.6 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a<500
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-2.7 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a>2500
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-2.8 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a>1900
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-2.9 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a>1100
+} {/SCAN TABLE t1/}
+do_execsql_test analyzeE-2.10 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a<1100
+} {/SEARCH TABLE t1 USING INDEX t1a/}
+do_execsql_test analyzeE-2.11 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a<1900
+} {/SCAN TABLE t1/}
+
+# Now do a range query on the second term of an ASCENDING index
+# where the first term is constrained by equality.
+#
+do_execsql_test analyzeE-3.0 {
+  DROP TABLE t1;
+  CREATE TABLE t1(a,b,c);
+  WITH RECURSIVE
+    cnt(x) AS (VALUES(1000) UNION ALL SELECT x+1 FROM cnt WHERE x<2000)
+  INSERT INTO t1(a,b,c) SELECT x, x, 123 FROM cnt;
+  CREATE INDEX t1ca ON t1(c,a);
+  ANALYZE;
+} {}
+do_execsql_test analyzeE-3.1 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500 AND c=123;
+} {/SCAN TABLE t1/}
+do_execsql_test analyzeE-3.2 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000 AND c=123;
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-3.3 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750 AND c=123;
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-3.4 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 AND c=123
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-3.5 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 AND c=123
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-3.6 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a<500 AND c=123
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-3.7 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a>2500 AND c=123
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-3.8 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a>1900 AND c=123
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-3.9 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a>1100 AND c=123
+} {/SCAN TABLE t1/}
+do_execsql_test analyzeE-3.10 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a<1100 AND c=123
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-3.11 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a<1900 AND c=123
+} {/SCAN TABLE t1/}
+
+# Repeat the 3.x tests using a DESCENDING index
+#
+do_execsql_test analyzeE-4.0 {
+  DROP INDEX t1ca;
+  CREATE INDEX t1ca ON t1(c ASC,a DESC);
+  ANALYZE;
+} {}
+do_execsql_test analyzeE-4.1 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 500 AND 2500 AND c=123;
+} {/SCAN TABLE t1/}
+do_execsql_test analyzeE-4.2 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 2900 AND 3000 AND c=123;
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-4.3 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 1700 AND 1750 AND c=123;
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-4.4 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 1 AND 500 AND c=123
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-4.5 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a BETWEEN 3000 AND 3000000 AND c=123
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-4.6 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a<500 AND c=123
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-4.7 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a>2500 AND c=123
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-4.8 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a>1900 AND c=123
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-4.9 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a>1100 AND c=123
+} {/SCAN TABLE t1/}
+do_execsql_test analyzeE-4.10 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a<1100 AND c=123
+} {/SEARCH TABLE t1 USING INDEX t1ca/}
+do_execsql_test analyzeE-4.11 {
+  EXPLAIN QUERY PLAN
+  SELECT * FROM t1 WHERE a<1900 AND c=123
+} {/SCAN TABLE t1/}
+
+finish_test