]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Enhancements to skip-scan such that it is operable when a middle column of
authordrh <drh@noemail.net>
Wed, 20 Aug 2014 23:38:07 +0000 (23:38 +0000)
committerdrh <drh@noemail.net>
Wed, 20 Aug 2014 23:38:07 +0000 (23:38 +0000)
an index is skipped while the left-most column is constrained in the WHERE
clause.

FossilOrigin-Name: bc985caa7816f1f873ad8e4467c5278399f315ce

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

index 0e557551980f02d8ed62e42403a240154dc49de8..928130ab8aba91a303bf496b1bc1cb4fc3fddc02 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C A\ssmall\sperformance\simprovement\sin\sfreeSpace()\sby\sspecial-casing\sthe\nrelatively\scommon\scase\sof\san\sempty\sfreelist.
-D 2014-08-20T18:43:44.510
+C Enhancements\sto\sskip-scan\ssuch\sthat\sit\sis\soperable\swhen\sa\smiddle\scolumn\sof\nan\sindex\sis\sskipped\swhile\sthe\sleft-most\scolumn\sis\sconstrained\sin\sthe\sWHERE\nclause.
+D 2014-08-20T23:38:07.310
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -296,7 +296,7 @@ F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
 F src/wal.c 264df50a1b33124130b23180ded2e2c5663c652a
 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
 F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
-F src/where.c ab20f9c24a422ee8900831b343c3d1e5e7aca87b
+F src/where.c 4c499d185827a492643cf017ae5e3aa0523f9f18
 F src/whereInt.h 923820bee9726033a501a08d2fc69b9c1ee4feb3
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -832,6 +832,7 @@ F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
 F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
 F test/skipscan1.test 28c7faa41a0d7265040ecb0a0abd90c0904270b2
 F test/skipscan2.test d1d1450952b7275f0b0a3a981f0230532743951a
+F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
 F test/skipscan5.test d8b9692b702745a0e41c23f9da6beac81df01196
 F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
 F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
@@ -1186,7 +1187,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 fe4fd014b42b7b158ca968f1535b5636c67769f6
-R 865eceb09aea170bb70d44b771b85e6e
+P 49f44d355ff70744e4951baca2481c7c2b6c02b3
+R 96923099996337b045b25027695cfca6
 U drh
-Z 0631afdcc5729e41fc50a75336710200
+Z 1b9938878e462b798940573e6153541a
index 2bb2527d3056d4502a8b0711aec3f6d6b353da2f..c25a80761d1a2e7c6d77054c5def832614cb878e 100644 (file)
@@ -1 +1 @@
-49f44d355ff70744e4951baca2481c7c2b6c02b3
\ No newline at end of file
+bc985caa7816f1f873ad8e4467c5278399f315ce
\ No newline at end of file
index 9c30136e876227543c0622c3b63348c17b9ef101..6a4299cc9ada34ce65b52a6e9b68ac2b99a1f2b3 100644 (file)
@@ -3781,8 +3781,8 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
   sqlite3DebugPrintf(" %12s",
                      pItem->zAlias ? pItem->zAlias : pTab->zName);
   if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
-     const char *zName;
-     if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){
+    const char *zName;
+    if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){
       if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){
         int i = sqlite3Strlen30(zName) - 1;
         while( zName[i]!='_' ) i--;
@@ -3803,7 +3803,11 @@ static void whereLoopPrint(WhereLoop *p, WhereClause *pWC){
     sqlite3DebugPrintf(" %-19s", z);
     sqlite3_free(z);
   }
-  sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
+  if( p->wsFlags & WHERE_SKIPSCAN ){
+    sqlite3DebugPrintf(" f %05x %d-%d", p->wsFlags, p->nLTerm,p->u.btree.nSkip);
+  }else{
+    sqlite3DebugPrintf(" f %05x N %d", p->wsFlags, p->nLTerm);
+  }
   sqlite3DebugPrintf(" cost %d,%d,%d\n", p->rSetup, p->rRun, p->nOut);
 #ifdef SQLITE_ENABLE_TREE_EXPLAIN
   /* If the 0x100 bit of wheretracing is set, then show all of the constraint
@@ -4316,8 +4320,7 @@ static int whereLoopAddBtreeIndex(
   ** On the other hand, the extra seeks could end up being significantly
   ** more expensive.  */
   assert( 42==sqlite3LogEst(18) );
-  if( pTerm==0
-   && saved_nEq==saved_nSkip
+  if( saved_nEq==saved_nSkip
    && saved_nEq+1<pProbe->nKeyCol
    && pProbe->aiRowLogEst[saved_nEq+1]>=42  /* TUNING: Minimum for skip-scan */
    && (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
@@ -4328,9 +4331,17 @@ static int whereLoopAddBtreeIndex(
     pNew->aLTerm[pNew->nLTerm++] = 0;
     pNew->wsFlags |= WHERE_SKIPSCAN;
     nIter = pProbe->aiRowLogEst[saved_nEq] - pProbe->aiRowLogEst[saved_nEq+1];
+    if( pTerm ){
+      /* TUNING:  When estimating skip-scan for a term that is also indexable,
+      ** increase the cost of the skip-scan by 2x, to make it a little less
+      ** desirable than the regular index lookup. */
+      nIter += 10;  assert( 10==sqlite3LogEst(2) );
+    }
     pNew->nOut -= nIter;
     whereLoopAddBtreeIndex(pBuilder, pSrc, pProbe, nIter + nInMul);
     pNew->nOut = saved_nOut;
+    pNew->u.btree.nEq = saved_nEq;
+    pNew->u.btree.nSkip = saved_nSkip;
   }
   for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
     u16 eOp = pTerm->eOperator;   /* Shorthand for pTerm->eOperator */
diff --git a/test/skipscan3.test b/test/skipscan3.test
new file mode 100644 (file)
index 0000000..260d11c
--- /dev/null
@@ -0,0 +1,73 @@
+# 2014-08-20
+#
+# 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 of the "skip-scan" query strategy.
+# In particular, this file looks at skipping intermediate terms
+# in an index.  For example, if (a,b,c) are indexed, and we have
+# "WHERE a=?1 AND c=?2" - verify that skip-scan can still be used.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+do_execsql_test skipscan3-1.1 {
+  CREATE TABLE t1(a,b,c,d,PRIMARY KEY(a,b,c));
+  WITH RECURSIVE
+    c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000)
+  INSERT INTO t1(a,b,c,d)
+    SELECT 1, 1, x, printf('x%04d',x) FROM c;
+  ANALYZE;
+} {}
+
+# This version has long used skip-scan because of the "+a"
+#
+do_execsql_test skipscan3-1.2eqp {
+  EXPLAIN QUERY PLAN SELECT d FROM t1 WHERE +a=1 AND c=32;
+} {/*ANY(a) AND ANY(b)*/}
+do_execsql_test skipscan3-1.2 {
+  SELECT d FROM t1 WHERE +a=1 AND c=32;
+} {x0032}
+
+# This version (with "a" instead of "+a") should use skip-scan but
+# did not prior to changes implemented on 2014-08-20
+#
+do_execsql_test skipscan3-1.3eqp {
+  EXPLAIN QUERY PLAN SELECT d FROM t1 WHERE a=1 AND c=32;
+} {/*ANY(a) AND ANY(b)*/}
+do_execsql_test skipscan3-1.3 {
+  SELECT d FROM t1 WHERE a=1 AND c=32;
+} {x0032}
+
+# Repeat the test on a WITHOUT ROWID table
+#
+do_execsql_test skipscan3-2.1 {
+  CREATE TABLE t2(a,b,c,d,PRIMARY KEY(a,b,c)) WITHOUT ROWID;
+  WITH RECURSIVE
+    c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<1000)
+  INSERT INTO t2(a,b,c,d)
+    SELECT 1, 1, x, printf('x%04d',x) FROM c;
+  ANALYZE;
+} {}
+do_execsql_test skipscan3-2.2eqp {
+  EXPLAIN QUERY PLAN SELECT d FROM t2 WHERE +a=1 AND c=32;
+} {/*ANY(a) AND ANY(b)*/}
+do_execsql_test skipscan3-2.2 {
+  SELECT d FROM t2 WHERE +a=1 AND c=32;
+} {x0032}
+do_execsql_test skipscan3-2.3eqp {
+  EXPLAIN QUERY PLAN SELECT d FROM t2 WHERE a=1 AND c=32;
+} {/*ANY(a) AND ANY(b)*/}
+do_execsql_test skipscan3-2.3 {
+  SELECT d FROM t2 WHERE a=1 AND c=32;
+} {x0032}
+
+  
+finish_test