]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Backport check-in [9f9f32882501ac9] to provide EXPLAIN QUERY PLAN output for
authordrh <drh@noemail.net>
Fri, 15 Apr 2011 15:18:34 +0000 (15:18 +0000)
committerdrh <drh@noemail.net>
Fri, 15 Apr 2011 15:18:34 +0000 (15:18 +0000)
the count(*) optimization.  Also backport check-in [a8761a9128de945aa] to
prevent unordered indices from being used on a full table scan.  The first
backport was necessary in order to test the second.

FossilOrigin-Name: 8d924e160703e02958db9c9bc1fd2c600e01e606

manifest
manifest.uuid
src/select.c
test/unordered.test [new file with mode: 0644]

index 99d68efac001534edd5669c0d2c817634d843c29..72f0c8b551a9367583b1608534dda872338901e3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Back\sport\sthe\sunordered-index-hack\sto\sthe\s3.7.2\sbranch.
-D 2011-04-09T03:30:25.496
+C Backport\scheck-in\s[9f9f32882501ac9]\sto\sprovide\sEXPLAIN\sQUERY\sPLAN\soutput\sfor\nthe\scount(*)\soptimization.\s\sAlso\sbackport\scheck-in\s[a8761a9128de945aa]\sto\nprevent\sunordered\sindices\sfrom\sbeing\sused\son\sa\sfull\stable\sscan.\s\sThe\sfirst\nbackport\swas\snecessary\sin\sorder\sto\stest\sthe\ssecond.
+D 2011-04-15T15:18:34.932
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 543f91f24cd7fee774ecc0a61c19704c0c3e78fd
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -168,7 +168,7 @@ F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506
 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
 F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
-F src/select.c 7a673c43b49d5f05f76e9c5a8cafa02862cbb901
+F src/select.c a84089eb0147bdc16f487cf6f2670432eb673c2b
 F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
 F src/sqlite.h.in 2d72a6242df41c517e38eec8791abcf5484a36f1
 F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
@@ -760,6 +760,7 @@ F test/types.test 9a825ec8eea4e965d7113b74c76a78bb5240f2ac
 F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
 F test/types3.test a0f66bf12f80fad89493535474f7a6d16fa58150
 F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2
+F test/unordered.test 87ecfbb688f984d4aaf5716a343e260dd1fa2c6e
 F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172
 F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
 F test/vacuum.test 15ae6784e70428b8db64e95c92d84b19e507b719
@@ -848,7 +849,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 9eff470226c6f879bb1b24fb00b6786a816d8cfd
-R ec1275508098699736f727d15a36cea8
+P 803530209f9c8d4dcf8ed51b5a96aee1766ef79f
+R 725597da94f34e4749b884cb2782a777
 U drh
-Z 5ab4f56fbd19b59b57d4609d1b0ffbc9
+Z 8cf57ecd3590b1d454de4a08c8b4d635
index 5153a63e499f09e545159211b510105b743989b6..1c1de6ee89d2667f088610ad909d0baaa5dde7bf 100644 (file)
@@ -1 +1 @@
-803530209f9c8d4dcf8ed51b5a96aee1766ef79f
\ No newline at end of file
+8d924e160703e02958db9c9bc1fd2c600e01e606
\ No newline at end of file
index e059ea135dfef30b781eb4ba4a9cd4e5f061516d..191c580abc3d887810ab9fbe85e65268fbaaefba 100644 (file)
@@ -3533,6 +3533,32 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
   sqlite3ExprCacheClear(pParse);
 }
 
+/*
+** Add a single OP_Explain instruction to the VDBE to explain a simple
+** count(*) query ("SELECT count(*) FROM pTab").
+*/
+#ifndef SQLITE_OMIT_EXPLAIN
+static void explainSimpleCount(
+  Parse *pParse,                  /* Parse context */
+  Table *pTab,                    /* Table being queried */
+  Index *pIdx                     /* Index used to optimize scan, or NULL */
+){
+  if( pParse->explain==2 ){
+    char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s %s%s(~%d rows)",
+        pTab->zName, 
+        pIdx ? "USING COVERING INDEX " : "",
+        pIdx ? pIdx->zName : "",
+        pTab->nRowEst
+    );
+    sqlite3VdbeAddOp4(
+        pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC
+    );
+  }
+}
+#else
+# define explainSimpleCount(a,b,c)
+#endif
+
 /*
 ** Generate code for the SELECT statement given in the p argument.  
 **
@@ -4113,11 +4139,13 @@ int sqlite3Select(
         ** and pKeyInfo to the KeyInfo structure required to navigate the
         ** index.
         **
+        ** (2011-04-15) Do not do a full scan of an unordered index.
+        **
         ** In practice the KeyInfo structure will not be used. It is only 
         ** passed to keep OP_OpenRead happy.
         */
         for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
-          if( !pBest || pIdx->nColumn<pBest->nColumn ){
+          if( pIdx->bUnordered==0 && (!pBest || pIdx->nColumn<pBest->nColumn) ){
             pBest = pIdx;
           }
         }
@@ -4133,6 +4161,7 @@ int sqlite3Select(
         }
         sqlite3VdbeAddOp2(v, OP_Count, iCsr, sAggInfo.aFunc[0].iMem);
         sqlite3VdbeAddOp1(v, OP_Close, iCsr);
+        explainSimpleCount(pParse, pTab, pBest);
       }else
 #endif /* SQLITE_OMIT_BTREECOUNT */
       {
diff --git a/test/unordered.test b/test/unordered.test
new file mode 100644 (file)
index 0000000..82da803
--- /dev/null
@@ -0,0 +1,67 @@
+# 2011 April 9
+#
+# 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 regression tests for SQLite library.  
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+set testprefix unordered
+
+do_execsql_test 1.0 {
+  CREATE TABLE t1(a, b);
+  CREATE INDEX i1 ON t1(a);
+  INSERT INTO t1 VALUES(1, 'xxx');
+  INSERT INTO t1 SELECT a+1, b FROM t1;
+  INSERT INTO t1 SELECT a+2, b FROM t1;
+  INSERT INTO t1 SELECT a+4, b FROM t1;
+  INSERT INTO t1 SELECT a+8, b FROM t1;
+  INSERT INTO t1 SELECT a+16, b FROM t1;
+  INSERT INTO t1 SELECT a+32, b FROM t1;
+  INSERT INTO t1 SELECT a+64, b FROM t1;
+  ANALYZE;
+} {}
+
+foreach idxmode {ordered unordered} {
+  if {$idxmode == "unordered"} {
+    execsql { UPDATE sqlite_stat1 SET stat = stat || ' unordered' }
+    db close
+    sqlite3 db test.db
+  }
+  foreach {tn sql r(ordered) r(unordered)} {
+    1   "SELECT * FROM t1 ORDER BY a"
+        {0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}}
+        {0 0 0 {SCAN TABLE t1 (~128 rows)}}
+    2   "SELECT * FROM t1 WHERE a >?"
+        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?) (~32 rows)}}
+        {0 0 0 {SCAN TABLE t1 (~42 rows)}}
+    3   "SELECT * FROM t1 WHERE a = ? ORDER BY rowid"
+        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
+        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
+    4   "SELECT max(a) FROM t1"
+        {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (~1 rows)}}
+        {0 0 0 {SEARCH TABLE t1 (~1 rows)}}
+    5   "SELECT group_concat(b) FROM t1 GROUP BY a"
+        {0 0 0 {SCAN TABLE t1 USING INDEX i1 (~128 rows)}}
+        {0 0 0 {SCAN TABLE t1 (~128 rows)}}
+
+    6   "SELECT * FROM t1 WHERE a = ?"
+        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
+        {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?) (~1 rows)}}
+    7   "SELECT count(*) FROM t1"
+        {0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1(~128 rows)}}
+        {0 0 0 {SCAN TABLE t1 (~128 rows)}}
+  } {
+    do_eqp_test 1.$idxmode.$tn $sql $r($idxmode)
+  }
+}
+
+finish_test