]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Provide an estimated row count to stat_init() for STAT1 analysis.
authordrh <drh@noemail.net>
Tue, 17 Mar 2020 17:11:23 +0000 (17:11 +0000)
committerdrh <drh@noemail.net>
Tue, 17 Mar 2020 17:11:23 +0000 (17:11 +0000)
FossilOrigin-Name: 714419fe85cfdad22979183a94e4569c87740652758ab76b646753cf2b013b54

manifest
manifest.uuid
src/analyze.c
src/vdbe.c

index d9bcf9d7e465a03d4e60ce6ae3d8245c3899390b..0d201b4bd753a14575eeb57a56f4be10db47ce6a 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Remove\sthe\sSQLITE_OMIT_BTREECOUNT\soption.\s\sBtree\scount\sis\srequired.
-D 2020-03-17T13:41:51.882
+C Provide\san\sestimated\srow\scount\sto\sstat_init()\sfor\sSTAT1\sanalysis.
+D 2020-03-17T17:11:23.756
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -466,7 +466,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
 F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
 F src/alter.c f48a4423c8f198d7f1ae4940f74b606707d05384ac79fb219be8e3323af2a2de
-F src/analyze.c aaeb41ef74002ffef24363891f3205aa0d544dfc0eb56a859d142fe08f9bc608
+F src/analyze.c 0df49eed25e472ef00bfe12184548a5a51890e7cd650c40fe2681430bdcae9d1
 F src/attach.c fa5addce233a2bb2dfdefeee3b37000e154c47214d3269cab1bb331416e330db
 F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06
 F src/backup.c 5e617c087f1c2d6005c2ec694ce80d6e16bc68d906e1b1c556d7c7c2228b636b
@@ -603,7 +603,7 @@ F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78
 F src/utf.c 95fb6e03a5ca679045c5adccd05380f0addccabef5911abddcb06af069500ab7
 F src/util.c a285c1e026907b69fa2592bd05047a565a1d8a1aef2b73c924b6a8ffe772871a
 F src/vacuum.c 813b510ba887fee6492bcb11f2bf77d7eb58b232b83649136372e0a2fc17f4b9
-F src/vdbe.c 1f5e82e73bc8fa158c643ed289a3ae15c0b7cf3c5f75ab96cef5b5f0798fdfee
+F src/vdbe.c 45896ffb6241d1b001a73a84a480af25036de89bab4a74ed1814d9020384d420
 F src/vdbe.h 51282fbe819ee0e8eeeaab176240860d334c20a12b14f3b363e7f1a4e05d60b9
 F src/vdbeInt.h a17146053a1aa438474012998fe07e314f3df274a61491ad838ad85d848ac051
 F src/vdbeapi.c 1252d80c548711e47a6d84dae88ed4e95d3fbb4e7bd0eaa1347299af7efddf02
@@ -1860,7 +1860,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P c38ea4139d87535b789f43eb1e38b2dc4b8312352a721035283e67cf0f3d5067
-R 10acd344478148ed927d0774ca99ede6
+P a9bfa47aeea27e91611ba913d33e6635d2016e2c2ab78f9b0657f1bd8933e1a8
+R 83170381358df6124fa4b6f4f7b0bc2e
 U drh
-Z 526c8dc722a58bf8fb8a844ac4513f2a
+Z b22aba55e2c8d6bfe6ccc85eac867e5f
index 229109d8f9c132ad3b88ff3ea208ffaa470f1e5d..73b2e21252d9823a5e4236948d94be7333f91ad0 100644 (file)
@@ -1 +1 @@
-a9bfa47aeea27e91611ba913d33e6635d2016e2c2ab78f9b0657f1bd8933e1a8
\ No newline at end of file
+714419fe85cfdad22979183a94e4569c87740652758ab76b646753cf2b013b54
\ No newline at end of file
index 0df9297b7f3865fe677e1bf023c7f7816ccd1f29..a7f70102b1ff00c3eaa9547e89dbd6958f9d25b3 100644 (file)
@@ -280,7 +280,8 @@ struct StatSample {
 };                                                    
 struct StatAccum {
   sqlite3 *db;              /* Database connection, for malloc() */
-  tRowcnt nRow;             /* Number of rows in the entire table */
+  tRowcnt nEst;             /* Estimated number of rows */
+  tRowcnt nRow;             /* Number of rows visited so far */
   int nCol;                 /* Number of columns in index + pk/rowid */
   int nKeyCol;              /* Number of index columns w/o the pk/rowid */
   StatSample current;       /* Current row as a StatSample */
@@ -377,14 +378,12 @@ static void statAccumDestructor(void *pOld){
 ** are:
 **     N:    The number of columns in the index including the rowid/pk (note 1)
 **     K:    The number of columns in the index excluding the rowid/pk.
-**     C:    The number of rows in the index (note 2)
+**     C:    Estimated number of rows in the index
 **
 ** Note 1:  In the special case of the covering index that implements a
 ** WITHOUT ROWID table, N is the number of PRIMARY KEY columns, not the
 ** total number of columns in the table.
 **
-** Note 2:  C is only used for STAT4.
-**
 ** For indexes on ordinary rowid tables, N==K+1.  But for indexes on
 ** WITHOUT ROWID tables, N=K+P where P is the number of columns in the
 ** PRIMARY KEY of the table.  The covering index that implements the
@@ -439,6 +438,7 @@ static void statInit(
   }
 
   p->db = db;
+  p->nEst = sqlite3_value_int64(argv[2]);
   p->nRow = 0;
   p->nCol = nCol;
   p->nKeyCol = nKeyCol;
@@ -452,7 +452,7 @@ static void statInit(
 
     p->iGet = -1;
     p->mxSample = mxSample;
-    p->nPSample = (tRowcnt)(sqlite3_value_int64(argv[2])/(mxSample/3+1) + 1);
+    p->nPSample = (tRowcnt)(p->nEst/(mxSample/3+1) + 1);
     p->current.anLt = &p->current.anEq[nColUp];
     p->iPrn = 0x689e962d*(u32)nCol ^ 0xd0944565*(u32)sqlite3_value_int(argv[2]);
   
@@ -923,16 +923,16 @@ static const FuncDef statGetFuncdef = {
   {0}
 };
 
-static void callStatGet(Parse *pParse, int regStat4, int iParam, int regOut){
+static void callStatGet(Parse *pParse, int regStat, int iParam, int regOut){
 #ifdef SQLITE_ENABLE_STAT4
-  sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat4+1);
+  sqlite3VdbeAddOp2(pParse->pVdbe, OP_Integer, iParam, regStat+1);
 #elif SQLITE_DEBUG
   assert( iParam==STAT_GET_STAT1 );
 #else
   UNUSED_PARAMETER( iParam );
 #endif
-  assert( regOut!=regStat4 && regOut!=regStat4+1 );
-  sqlite3VdbeAddFunctionCall(pParse, 0, regStat4, regOut, 1+IsStat4,
+  assert( regOut!=regStat && regOut!=regStat+1 );
+  sqlite3VdbeAddFunctionCall(pParse, 0, regStat, regOut, 1+IsStat4,
                              &statGetFuncdef, 0);
 }
 
@@ -958,11 +958,9 @@ static void analyzeOneTable(
   int iDb;                     /* Index of database containing pTab */
   u8 needTableCnt = 1;         /* True to count the table */
   int regNewRowid = iMem++;    /* Rowid for the inserted record */
-  int regStat4 = iMem++;       /* Register to hold StatAccum object */
+  int regStat = iMem++;        /* Register to hold StatAccum object */
   int regChng = iMem++;        /* Index of changed index field */
-#ifdef SQLITE_ENABLE_STAT4
   int regRowid = iMem++;       /* Rowid argument passed to stat_push() */
-#endif
   int regTemp = iMem++;        /* Temporary use register */
   int regTabname = iMem++;     /* Register containing table name */
   int regIdxname = iMem++;     /* Register containing index name */
@@ -1091,21 +1089,24 @@ static void analyzeOneTable(
     **    (1) the number of columns in the index including the rowid
     **        (or for a WITHOUT ROWID table, the number of PK columns),
     **    (2) the number of columns in the key without the rowid/pk
-    **    (3) the number of rows in the index,
-    **
-    **
-    ** The third argument is only used for STAT4
+    **    (3) estimated number of rows in the index,
     */
+    sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat+1);
+    assert( regRowid==regStat+2 );
+    sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regRowid);
 #ifdef SQLITE_ENABLE_STAT4
     if( OptimizationEnabled(db, SQLITE_Stat4) ){
-      sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+3);
-    }else{
-      sqlite3VdbeAddOp2(v, OP_Integer, 0, regStat4+3);
-    }
+      sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regTemp);
+      addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
+      VdbeCoverage(v);
+    }else
 #endif
-    sqlite3VdbeAddOp2(v, OP_Integer, nCol, regStat4+1);
-    sqlite3VdbeAddOp2(v, OP_Integer, pIdx->nKeyCol, regStat4+2);
-    sqlite3VdbeAddFunctionCall(pParse, 0, regStat4+1, regStat4, 2+IsStat4,
+    {
+      addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
+      VdbeCoverage(v);
+      sqlite3VdbeAddOp3(v, OP_Count, iIdxCur, regTemp, 1);
+    }
+    sqlite3VdbeAddFunctionCall(pParse, 0, regStat+1, regStat, 3,
                                &statInitFuncdef, 0);
 
     /* Implementation of the following:
@@ -1116,8 +1117,6 @@ static void analyzeOneTable(
     **   goto next_push_0;
     **
     */
-    addrRewind = sqlite3VdbeAddOp1(v, OP_Rewind, iIdxCur);
-    VdbeCoverage(v);
     sqlite3VdbeAddOp2(v, OP_Integer, 0, regChng);
     addrNextRow = sqlite3VdbeCurrentAddr(v);
 
@@ -1186,7 +1185,7 @@ static void analyzeOneTable(
     */
 #ifdef SQLITE_ENABLE_STAT4
     if( OptimizationEnabled(db, SQLITE_Stat4) ){
-      assert( regRowid==(regStat4+2) );
+      assert( regRowid==(regStat+2) );
       if( HasRowid(pTab) ){
         sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid);
       }else{
@@ -1204,13 +1203,13 @@ static void analyzeOneTable(
       }
     }
 #endif
-    assert( regChng==(regStat4+1) );
-    sqlite3VdbeAddFunctionCall(pParse, 1, regStat4, regTemp, 2+IsStat4,
+    assert( regChng==(regStat+1) );
+    sqlite3VdbeAddFunctionCall(pParse, 1, regStat, regTemp, 2+IsStat4,
                                &statPushFuncdef, 0);
     sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); VdbeCoverage(v);
 
     /* Add the entry to the stat1 table. */
-    callStatGet(pParse, regStat4, STAT_GET_STAT1, regStat1);
+    callStatGet(pParse, regStat, STAT_GET_STAT1, regStat1);
     assert( "BBB"[0]==SQLITE_AFF_TEXT );
     sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regTemp, "BBB", 0);
     sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
@@ -1236,12 +1235,12 @@ static void analyzeOneTable(
       pParse->nMem = MAX(pParse->nMem, regCol+nCol);
 
       addrNext = sqlite3VdbeCurrentAddr(v);
-      callStatGet(pParse, regStat4, STAT_GET_ROWID, regSampleRowid);
+      callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid);
       addrIsNull = sqlite3VdbeAddOp1(v, OP_IsNull, regSampleRowid);
       VdbeCoverage(v);
-      callStatGet(pParse, regStat4, STAT_GET_NEQ, regEq);
-      callStatGet(pParse, regStat4, STAT_GET_NLT, regLt);
-      callStatGet(pParse, regStat4, STAT_GET_NDLT, regDLt);
+      callStatGet(pParse, regStat, STAT_GET_NEQ, regEq);
+      callStatGet(pParse, regStat, STAT_GET_NLT, regLt);
+      callStatGet(pParse, regStat, STAT_GET_NDLT, regDLt);
       sqlite3VdbeAddOp4Int(v, seekOp, iTabCur, addrNext, regSampleRowid, 0);
       VdbeCoverage(v);
       for(i=0; i<nCol; i++){
index 246442b47931cd725f1b31211623a8c2efff82e7..4eac7be647cfcf92921a4184cf9eacfab97be6b3 100644 (file)
@@ -3187,11 +3187,15 @@ case OP_MakeRecord: {
   break;
 }
 
-/* Opcode: Count P1 P2 * * *
+/* Opcode: Count P1 P2 p3 * *
 ** Synopsis: r[P2]=count()
 **
 ** Store the number of entries (an integer value) in the table or index 
-** opened by cursor P1 in register P2
+** opened by cursor P1 in register P2.
+**
+** If P3==0, then an exact count is obtained, which involves visiting
+** every btree page of the table.  But if P3 is non-zero, an estimate
+** is returned based on the current cursor position.  
 */
 case OP_Count: {         /* out2 */
   i64 nEntry;
@@ -3200,9 +3204,13 @@ case OP_Count: {         /* out2 */
   assert( p->apCsr[pOp->p1]->eCurType==CURTYPE_BTREE );
   pCrsr = p->apCsr[pOp->p1]->uc.pCursor;
   assert( pCrsr );
-  nEntry = 0;  /* Not needed.  Only used to silence a warning. */
-  rc = sqlite3BtreeCount(db, pCrsr, &nEntry);
-  if( rc ) goto abort_due_to_error;
+  if( pOp->p3 ){
+    nEntry = sqlite3BtreeRowCountEst(pCrsr);
+  }else{
+    nEntry = 0;  /* Not needed.  Only used to silence a warning. */
+    rc = sqlite3BtreeCount(db, pCrsr, &nEntry);
+    if( rc ) goto abort_due_to_error;
+  }
   pOut = out2Prerelease(p, pOp);
   pOut->u.i = nEntry;
   goto check_for_interrupt;