]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Try to remember statistics from ANALYZE using LogEst instead of u64. log-stats
authordrh <drh@noemail.net>
Mon, 7 Oct 2013 16:53:50 +0000 (16:53 +0000)
committerdrh <drh@noemail.net>
Mon, 7 Oct 2013 16:53:50 +0000 (16:53 +0000)
FossilOrigin-Name: 8e78557a40a6b97009852f5b72e68d6483fb00fc

manifest
manifest.uuid
src/analyze.c
src/build.c
src/select.c
src/sqliteInt.h
src/util.c
src/where.c

index 824d937e6444b9976c5851d9ca4c4475cf62a07f..a344626fc7e35869326524581987cddc491e0558 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Merge\sbug\sfixes\sfrom\strunk.
-D 2013-10-07T10:48:06.076
+C Try\sto\sremember\sstatistics\sfrom\sANALYZE\susing\sLogEst\sinstead\sof\su64.
+D 2013-10-07T16:53:50.515
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -157,7 +157,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
 F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
 F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
-F src/analyze.c c27da55795a11d09bea74259782c3e11e9750534
+F src/analyze.c 3994309c21b7324217cd32225b7abb5cb1bd1946
 F src/attach.c 0a17c9364895316ca4f52d06a97a72c0af1ae8b3
 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
 F src/backup.c 2f1987981139bd2f6d8c728d64bf09fb387443c3
@@ -166,7 +166,7 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
 F src/btree.c d5720cbb21ae56e7e5b07847e05e5b203818acac
 F src/btree.h bfe0e8c5759b4ec77b0d18390064a6ef3cdffaaf
 F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
-F src/build.c ea07ec35354cdcd017b128679391320220030336
+F src/build.c 46bb89df0a204eb7154874f966f11d16a7fbced7
 F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
@@ -216,12 +216,12 @@ F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
 F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
 F src/resolve.c 7459801d02997b07e8b8da85ef255392ba1d022b
 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
-F src/select.c 13be733297f415b388444a2e296d23569cd83b8a
+F src/select.c 19611e6da6646a1090164b29d6b23b7c8e7364ea
 F src/shell.c 5ee50ca3e35453bbd6ccdf1bdd0f6bbe9738e9fb
 F src/sqlite.h.in ec40aa958a270416fb04b4f72210357bf163d2c5
 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
-F src/sqliteInt.h 5dbfc960fb39dbb55ba16697f453b03cd759b04a
+F src/sqliteInt.h a5fa87b540662fb552ba81c0d4eeb368aebb5af7
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -275,7 +275,7 @@ F src/tokenize.c 70061085a51f2f4fc15ece94f32c03bcb78e63b2
 F src/trigger.c ba0a883cd536b7dfdd4df3733001f5372a4299da
 F src/update.c f5182157f5d0d0a97bc5f5e3c9bdba0dfbe08f08
 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
-F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
+F src/util.c 2f0c9b1f884d038eb90f48cf17042a88dc1629d3
 F src/vacuum.c f313bc97123a4dd4bfd3f50a00c4d44c08a5b1b7
 F src/vdbe.c 56e648f5ba9a91810caf216857adfed9039cd174
 F src/vdbe.h 4f554b5627f26710c4c36d919110a3fc611ca5c4
@@ -290,7 +290,7 @@ F src/vtab.c 5a423b042eb1402ef77697d03d6a67378d97bc8d
 F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
 F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
-F src/where.c 72c6c205e53ae72d2d235705bb2b040d70fff2e2
+F src/where.c 7916e32a4d7f8cc891a08de09380ef519415d275
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
@@ -1121,7 +1121,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P e9e932aa400f217e383cda9922fbde8a4356f57a 0aca31e1514b3df254c049b4251bcb199831681a
-R 58571132dec54639078eadde66ba0889
+P 1d7b2dc0eae70c0c0e523b715acf758bb4cfa9ac
+R faf619696f929769ec0cefbeba9e27c2
+T *branch * log-stats
+T *sym-log-stats *
+T -sym-row-size-est *
 U drh
-Z 412c711013eb3a5449cb7f9aec9f3c69
+Z 72baf94bdfc7ce8839761e1732e0e2d4
index eb89607625913526da3d275a9773bd196448f742..8c783a8a317432f17581d6c46c0dec2be75906a6 100644 (file)
@@ -1 +1 @@
-1d7b2dc0eae70c0c0e523b715acf758bb4cfa9ac
\ No newline at end of file
+8e78557a40a6b97009852f5b72e68d6483fb00fc
\ No newline at end of file
index 84232ebe5d8f2761379bfac719d95fa59dcc5875..8b0d9797e3347a7ee04d9e03ccc9348ad8e4195c 100644 (file)
@@ -1252,13 +1252,13 @@ struct analysisInfo {
 static void decodeIntArray(
   char *zIntArray,       /* String containing int array to decode */
   int nOut,              /* Number of slots in aOut[] */
-  tRowcnt *aOut,         /* Store integers here */
+  LogEst *aOut,          /* Convert values to 10*log2() and store here */
   Index *pIndex          /* Handle extra flags for this index, if not NULL */
 ){
   char *z = zIntArray;
   int c;
   int i;
-  tRowcnt v;
+  u64 v;
 
 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
   if( z==0 ) z = "";
@@ -1271,7 +1271,7 @@ static void decodeIntArray(
       v = v*10 + c - '0';
       z++;
     }
-    aOut[i] = v;
+    aOut[i] = sqlite3LogEst(v);
     if( *z==' ' ) z++;
   }
   if( pIndex ){
@@ -1368,10 +1368,10 @@ static void initAvgEq(Index *pIdx){
     int iCol;
     for(iCol=0; iCol<pIdx->nColumn; iCol++){
       int i;                    /* Used to iterate through samples */
-      tRowcnt sumEq = 0;        /* Sum of the nEq values */
-      tRowcnt nSum = 0;         /* Number of terms contributing to sumEq */
-      tRowcnt avgEq = 0;
-      tRowcnt nDLt = pFinal->anDLt[iCol];
+      u64 sumEq = 0;        /* Sum of the nEq values */
+      u64 nSum = 0;         /* Number of terms contributing to sumEq */
+      u64 avgEq = 0;
+      u64 nDLt = sqlite3LogEstToInt(pFinal->anDLt[iCol]);
 
       /* Set nSum to the number of distinct (iCol+1) field prefixes that
       ** occur in the stat4 table for this index before pFinal. Set
@@ -1380,15 +1380,15 @@ static void initAvgEq(Index *pIdx){
       ** prefixes).  */
       for(i=0; i<(pIdx->nSample-1); i++){
         if( aSample[i].anDLt[iCol]!=aSample[i+1].anDLt[iCol] ){
-          sumEq += aSample[i].anEq[iCol];
+          sumEq += sqlite3LogEstToInt(aSample[i].anEq[iCol]);
           nSum++;
         }
       }
       if( nDLt>nSum ){
-        avgEq = (pFinal->anLt[iCol] - sumEq)/(nDLt - nSum);
+        avgEq = (sqlite3LogEstToInt(pFinal->anLt[iCol]) - sumEq)/(nDLt - nSum);
       }
-      if( avgEq==0 ) avgEq = 1;
-      pIdx->aAvgEq[iCol] = avgEq;
+      if( avgEq<=0 ) avgEq = 1;
+      pIdx->aAvgEq[iCol] = sqlite3LogEst(avgEq);
       if( pIdx->nSampleCol==1 ) break;
     }
   }
@@ -1438,7 +1438,7 @@ static int loadStatTbl(
     int nSample;    /* Number of samples */
     int nByte;      /* Bytes of space required */
     int i;          /* Bytes of space required */
-    tRowcnt *pSpace;
+    LogEst *pSpace;
 
     zIndex = (char *)sqlite3_column_text(pStmt, 0);
     if( zIndex==0 ) continue;
@@ -1454,15 +1454,15 @@ static int loadStatTbl(
     }
     pIdx->nSampleCol = nIdxCol;
     nByte = sizeof(IndexSample) * nSample;
-    nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
-    nByte += nAvgCol * sizeof(tRowcnt);     /* Space for Index.aAvgEq[] */
+    nByte += sizeof(LogEst) * nIdxCol * 3 * nSample;
+    nByte += nAvgCol * sizeof(LogEst);     /* Space for Index.aAvgEq[] */
 
     pIdx->aSample = sqlite3DbMallocZero(db, nByte);
     if( pIdx->aSample==0 ){
       sqlite3_finalize(pStmt);
       return SQLITE_NOMEM;
     }
-    pSpace = (tRowcnt*)&pIdx->aSample[nSample];
+    pSpace = (LogEst*)&pIdx->aSample[nSample];
     pIdx->aAvgEq = pSpace; pSpace += nAvgCol;
     for(i=0; i<nSample; i++){
       pIdx->aSample[i].anEq = pSpace; pSpace += nIdxCol;
index 3c8d22d3cdfc57a6f91dda5bc4e19862b4b16b4c..e5e4eeb90859fc058765fb516394404d25f9b797 100644 (file)
@@ -879,7 +879,7 @@ void sqlite3StartTable(
   pTable->iPKey = -1;
   pTable->pSchema = db->aDb[iDb].pSchema;
   pTable->nRef = 1;
-  pTable->nRowEst = 1000000;
+  pTable->nRowEst = 200;
   assert( pParse->pNewTable==0 );
   pParse->pNewTable = pTable;
 
@@ -2722,7 +2722,7 @@ Index *sqlite3CreateIndex(
   nCol = pList->nExpr;
   pIndex = sqlite3DbMallocZero(db, 
       ROUND8(sizeof(Index)) +              /* Index structure  */
-      ROUND8(sizeof(tRowcnt)*(nCol+1)) +   /* Index.aiRowEst   */
+      ROUND8(sizeof(LogEst)*(nCol+1)) +    /* Index.aiRowEst   */
       sizeof(char *)*nCol +                /* Index.azColl     */
       sizeof(int)*nCol +                   /* Index.aiColumn   */
       sizeof(u8)*nCol +                    /* Index.aSortOrder */
@@ -2733,9 +2733,9 @@ Index *sqlite3CreateIndex(
     goto exit_create_index;
   }
   zExtra = (char*)pIndex;
-  pIndex->aiRowEst = (tRowcnt*)&zExtra[ROUND8(sizeof(Index))];
+  pIndex->aiRowEst = (LogEst*)&zExtra[ROUND8(sizeof(Index))];
   pIndex->azColl = (char**)
-     ((char*)pIndex->aiRowEst + ROUND8(sizeof(tRowcnt)*nCol+1));
+     ((char*)pIndex->aiRowEst + ROUND8(sizeof(LogEst)*nCol+1));
   assert( EIGHT_BYTE_ALIGNMENT(pIndex->aiRowEst) );
   assert( EIGHT_BYTE_ALIGNMENT(pIndex->azColl) );
   pIndex->aiColumn = (int *)(&pIndex->azColl[nCol]);
@@ -3014,19 +3014,20 @@ exit_create_index:
 ** are based on typical values found in actual indices.
 */
 void sqlite3DefaultRowEst(Index *pIdx){
-  tRowcnt *a = pIdx->aiRowEst;
+  LogEst *a = pIdx->aiRowEst;
   int i;
-  tRowcnt n;
+  LogEst n;
   assert( a!=0 );
   a[0] = pIdx->pTable->nRowEst;
-  if( a[0]<10 ) a[0] = 10;
-  n = 10;
+  assert( 33==sqlite3LogEst(10) );
+  if( a[0]<34 ){ a[0] = 34; }
+  n = 34;
   for(i=1; i<=pIdx->nColumn; i++){
     a[i] = n;
-    if( n>5 ) n--;
+    if( n>24 ) n -= 2;
   }
   if( pIdx->onError!=OE_None ){
-    a[pIdx->nColumn] = 1;
+    a[pIdx->nColumn] = 0;
   }
 }
 
index f9c7835fd27315a08e9b43fb90233e02cbc1241a..eee681ff2032b9ba767b19be74c264eba95ceca7 100644 (file)
@@ -1480,7 +1480,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect){
   assert( db->lookaside.bEnabled==0 );
   pTab->nRef = 1;
   pTab->zName = 0;
-  pTab->nRowEst = 1000000;
+  pTab->nRowEst = 200;
   selectColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol);
   selectAddColumnTypeAndCollation(pParse, pTab->nCol, pTab->aCol, pSelect);
   pTab->iPKey = -1;
@@ -3398,7 +3398,7 @@ static int selectExpander(Walker *pWalker, Select *p){
       while( pSel->pPrior ){ pSel = pSel->pPrior; }
       selectColumnsFromExprList(pParse, pSel->pEList, &pTab->nCol, &pTab->aCol);
       pTab->iPKey = -1;
-      pTab->nRowEst = 1000000;
+      pTab->nRowEst = 200;
       pTab->tabFlags |= TF_Ephemeral;
 #endif
     }else{
index b02fb12b2621bbd052139a1f487ba5a784b560ea..fe8e3f919a3cdd612ff43003097fbce309e55826 100644 (file)
@@ -1382,11 +1382,11 @@ struct Table {
 #ifndef SQLITE_OMIT_CHECK
   ExprList *pCheck;    /* All CHECK constraints */
 #endif
-  tRowcnt nRowEst;     /* Estimated rows in table - from sqlite_stat1 table */
   int tnum;            /* Root BTree node for this table (see note above) */
   i16 iPKey;           /* If not negative, use aCol[iPKey] as the primary key */
   i16 nCol;            /* Number of columns in this table */
   u16 nRef;            /* Number of pointers to this Table */
+  LogEst nRowEst;      /* Estimated number of rows in the table */
   LogEst szTabRow;     /* Estimated size of each table row in bytes */
   u8 tabFlags;         /* Mask of TF_* values */
   u8 keyConf;          /* What to do in case of uniqueness conflict on iPKey */
@@ -1577,7 +1577,7 @@ struct UnpackedRecord {
 struct Index {
   char *zName;             /* Name of this index */
   int *aiColumn;           /* Which columns are used by this index.  1st is 0 */
-  tRowcnt *aiRowEst;       /* From ANALYZE: Est. rows selected by each column */
+  LogEst *aiRowEst;        /* From ANALYZE: Est. rows selected by each column */
   Table *pTable;           /* The SQL table being indexed */
   char *zColAff;           /* String defining the affinity of each column */
   Index *pNext;            /* The next index associated with the same table */
@@ -1595,7 +1595,7 @@ struct Index {
 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
   int nSample;             /* Number of elements in aSample[] */
   int nSampleCol;          /* Size of IndexSample.anEq[] and so on */
-  tRowcnt *aAvgEq;         /* Average nEq values for keys not in aSample */
+  LogEst *aAvgEq;          /* Average nEq values for keys not in aSample */
   IndexSample *aSample;    /* Samples of the left-most key */
 #endif
 };
@@ -1608,9 +1608,9 @@ struct Index {
 struct IndexSample {
   void *p;          /* Pointer to sampled record */
   int n;            /* Size of record in bytes */
-  tRowcnt *anEq;    /* Est. number of rows where the key equals this sample */
-  tRowcnt *anLt;    /* Est. number of rows where key is less than this sample */
-  tRowcnt *anDLt;   /* Est. number of distinct keys less than this sample */
+  LogEst *anEq;     /* Est. number of rows where the key equals this sample */
+  LogEst *anLt;     /* Est. number of rows where key is less than this sample */
+  LogEst *anDLt;    /* Est. number of distinct keys less than this sample */
 };
 
 /*
index 50ffd98650bf862985cd453ace8830063847ebf9..72e6e17e7554d9a74eccd04d8856765ab5b3e69b 100644 (file)
@@ -1213,7 +1213,6 @@ void sqlite3FileSuffix3(const char *zBaseFilename, char *z){
 ** Find (an approximate) sum of two LogEst values.  This computation is
 ** not a simple "+" operator because LogEst is stored as a logarithmic
 ** value.
-** 
 */
 LogEst sqlite3LogEstAdd(LogEst a, LogEst b){
   static const unsigned char x[] = {
index 98af69b10c152fea9388726f6965328c0100981b..0f160b80b782392276595b294ca9846f83f99faf 100644 (file)
@@ -2328,7 +2328,7 @@ static void whereKeyStats(
   Index *pIdx,                /* Index to consider domain of */
   UnpackedRecord *pRec,       /* Vector of values to consider */
   int roundUp,                /* Round up if true.  Round down if false */
-  tRowcnt *aStat              /* OUT: stats written here */
+  LogEst *aStat               /* OUT: stats written here */
 ){
   IndexSample *aSample = pIdx->aSample;
   int iCol;                   /* Index of required stats in anEq[] etc. */
@@ -2381,15 +2381,16 @@ static void whereKeyStats(
     aStat[0] = aSample[i].anLt[iCol];
     aStat[1] = aSample[i].anEq[iCol];
   }else{
-    tRowcnt iLower, iUpper, iGap;
+    LogEst iLower, iUpper, iGap;
     if( i==0 ){
       iLower = 0;
       iUpper = aSample[0].anLt[iCol];
     }else{
       iUpper = i>=pIdx->nSample ? pIdx->aiRowEst[0] : aSample[i].anLt[iCol];
-      iLower = aSample[i-1].anEq[iCol] + aSample[i-1].anLt[iCol];
+      iLower = sqlite3LogEstAdd(aSample[i-1].anEq[iCol],
+                                aSample[i-1].anLt[iCol]);
     }
-    aStat[1] = (pIdx->nColumn>iCol ? pIdx->aAvgEq[iCol] : 1);
+    aStat[1] = (pIdx->nColumn>iCol ? pIdx->aAvgEq[iCol] : 0);
     if( iLower>=iUpper ){
       iGap = 0;
     }else{
@@ -2466,7 +2467,7 @@ static int whereRangeScanEst(
    && OptimizationEnabled(pParse->db, SQLITE_Stat3) 
   ){
     UnpackedRecord *pRec = pBuilder->pRec;
-    tRowcnt a[2];
+    LogEst a[2];
     u8 aff;
 
     /* Variable iLower will be set to the estimate of the number of rows in 
@@ -2486,8 +2487,8 @@ static int whereRangeScanEst(
     ** is either ($P) or ($P:$U). Again, even if $U is available, both values
     ** of iUpper are requested of whereKeyStats() and the smaller used.
     */
-    tRowcnt iLower;
-    tRowcnt iUpper;
+    LogEst iLower;
+    LogEst iUpper;
 
     if( nEq==p->nColumn ){
       aff = SQLITE_AFF_INTEGER;
@@ -2503,7 +2504,7 @@ static int whereRangeScanEst(
       ** have been requested when testing key $P in whereEqualScanEst().  */
       whereKeyStats(pParse, p, pRec, 0, a);
       iLower = a[0];
-      iUpper = a[0] + a[1];
+      iUpper = sqlite3LogEstAdd(a[0],a[1]);
     }
 
     /* If possible, improve on the iLower estimate using ($P:$L). */
@@ -2513,9 +2514,9 @@ static int whereRangeScanEst(
       assert( (pLower->eOperator & (WO_GT|WO_GE))!=0 );
       rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
       if( rc==SQLITE_OK && bOk ){
-        tRowcnt iNew;
+        LogEst iNew;
         whereKeyStats(pParse, p, pRec, 0, a);
-        iNew = a[0] + ((pLower->eOperator & WO_GT) ? a[1] : 0);
+        iNew = sqlite3LogEstAdd(a[0],((pLower->eOperator & WO_GT) ? a[1] : 0));
         if( iNew>iLower ) iLower = iNew;
         nOut--;
       }
@@ -2528,9 +2529,9 @@ static int whereRangeScanEst(
       assert( (pUpper->eOperator & (WO_LT|WO_LE))!=0 );
       rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk);
       if( rc==SQLITE_OK && bOk ){
-        tRowcnt iNew;
+        LogEst iNew;
         whereKeyStats(pParse, p, pRec, 1, a);
-        iNew = a[0] + ((pUpper->eOperator & WO_LE) ? a[1] : 0);
+        iNew = sqlite3LogEstAdd(a[0],((pUpper->eOperator & WO_LE) ? a[1] : 0));
         if( iNew<iUpper ) iUpper = iNew;
         nOut--;
       }
@@ -2538,17 +2539,17 @@ static int whereRangeScanEst(
 
     pBuilder->pRec = pRec;
     if( rc==SQLITE_OK ){
-      if( iUpper>iLower ){
-        nNew = sqlite3LogEst(iUpper - iLower);
-      }else{
-        nNew = 10;        assert( 10==sqlite3LogEst(2) );
-      }
+      if( iUpper<=iLower ) iUpper = iLower+1;
+      nNew = sqlite3LogEst(sqlite3LogEstToInt(iUpper)
+                             - sqlite3LogEstToInt(iLower));
       if( nNew<nOut ){
         nOut = nNew;
       }
       *pnOut = (LogEst)nOut;
-      WHERETRACE(0x100, ("range scan regions: %u..%u  est=%d\n",
-                         (u32)iLower, (u32)iUpper, nOut));
+      WHERETRACE(0x100, ("range scan regions: %llu..%llu  est=%d\n",
+                         sqlite3LogEstToInt(iLower),
+                         sqlite3LogEstToInt(iUpper),
+                         nOut));
       return SQLITE_OK;
     }
   }
@@ -2596,14 +2597,14 @@ static int whereEqualScanEst(
   Parse *pParse,       /* Parsing & code generating context */
   WhereLoopBuilder *pBuilder,
   Expr *pExpr,         /* Expression for VALUE in the x=VALUE constraint */
-  tRowcnt *pnRow       /* Write the revised row estimate here */
+  LogEst *pnRow        /* Write the revised row estimate here */
 ){
   Index *p = pBuilder->pNew->u.btree.pIndex;
   int nEq = pBuilder->pNew->u.btree.nEq;
   UnpackedRecord *pRec = pBuilder->pRec;
   u8 aff;                   /* Column affinity */
   int rc;                   /* Subfunction return code */
-  tRowcnt a[2];             /* Statistics */
+  LogEst a[2];              /* Statistics */
   int bOk;
 
   assert( nEq>=1 );
@@ -2633,7 +2634,8 @@ static int whereEqualScanEst(
   pBuilder->nRecValid = nEq;
 
   whereKeyStats(pParse, p, pRec, 0, a);
-  WHERETRACE(0x100,("equality scan regions: %d\n", (int)a[1]));
+  WHERETRACE(0x100,("equality scan regions: %d (%llu)\n", a[1],
+                    sqlite3LogEstToInt(a[1])));
   *pnRow = a[1];
   
   return rc;
@@ -2661,27 +2663,28 @@ static int whereInScanEst(
   Parse *pParse,       /* Parsing & code generating context */
   WhereLoopBuilder *pBuilder,
   ExprList *pList,     /* The value list on the RHS of "x IN (v1,v2,v3,...)" */
-  tRowcnt *pnRow       /* Write the revised row estimate here */
+  LogEst *pnRow        /* Write the revised row estimate here */
 ){
   Index *p = pBuilder->pNew->u.btree.pIndex;
   int nRecValid = pBuilder->nRecValid;
   int rc = SQLITE_OK;     /* Subfunction return code */
-  tRowcnt nEst;           /* Number of rows for a single term */
-  tRowcnt nRowEst = 0;    /* New estimate of the number of rows */
+  LogEst nEst;            /* Number of rows for a single term */
+  u64 nRowEst = 0;        /* New estimate of the number of rows */
   int i;                  /* Loop counter */
 
   assert( p->aSample!=0 );
   for(i=0; rc==SQLITE_OK && i<pList->nExpr; i++){
     nEst = p->aiRowEst[0];
     rc = whereEqualScanEst(pParse, pBuilder, pList->a[i].pExpr, &nEst);
-    nRowEst += nEst;
+    nRowEst += sqlite3LogEstToInt(nEst);
     pBuilder->nRecValid = nRecValid;
   }
 
   if( rc==SQLITE_OK ){
-    if( nRowEst > p->aiRowEst[0] ) nRowEst = p->aiRowEst[0];
-    *pnRow = nRowEst;
-    WHERETRACE(0x100,("IN row estimate: est=%g\n", nRowEst));
+    nEst = sqlite3LogEst(nRowEst);
+    if( nEst > p->aiRowEst[0] ) nEst = p->aiRowEst[0];
+    *pnRow = nEst;
+    WHERETRACE(0x100,("IN row estimate: est=%d (%llu)\n", nEst, nRowEst));
   }
   assert( pBuilder->nRecValid==nRecValid );
   return rc;
@@ -4251,8 +4254,8 @@ static int whereLoopAddBtreeIndex(
   assert( pNew->u.btree.nEq<=pProbe->nColumn );
   if( pNew->u.btree.nEq < pProbe->nColumn ){
     iCol = pProbe->aiColumn[pNew->u.btree.nEq];
-    nRowEst = sqlite3LogEst(pProbe->aiRowEst[pNew->u.btree.nEq+1]);
-    if( nRowEst==0 && pProbe->onError==OE_None ) nRowEst = 1;
+    nRowEst = pProbe->aiRowEst[pNew->u.btree.nEq+1];
+    if( nRowEst<10 && pProbe->onError==OE_None ) nRowEst = 10;
   }else{
     iCol = -1;
     nRowEst = 0;
@@ -4265,7 +4268,7 @@ static int whereLoopAddBtreeIndex(
   saved_prereq = pNew->prereq;
   saved_nOut = pNew->nOut;
   pNew->rSetup = 0;
-  rLogSize = estLog(sqlite3LogEst(pProbe->aiRowEst[0]));
+  rLogSize = estLog(pProbe->aiRowEst[0]);
   for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){
     int nIn = 0;
 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
@@ -4346,7 +4349,7 @@ static int whereLoopAddBtreeIndex(
      && OptimizationEnabled(db, SQLITE_Stat3) 
     ){
       Expr *pExpr = pTerm->pExpr;
-      tRowcnt nOut = 0;
+      LogEst nOut = pNew->nOut;
       if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){
         testcase( pTerm->eOperator & WO_EQ );
         testcase( pTerm->eOperator & WO_ISNULL );
@@ -4355,11 +4358,8 @@ static int whereLoopAddBtreeIndex(
              &&  !ExprHasProperty(pExpr, EP_xIsSelect)  ){
         rc = whereInScanEst(pParse, pBuilder, pExpr->x.pList, &nOut);
       }
-      assert( nOut==0 || rc==SQLITE_OK );
-      if( nOut ){
-        nOut = sqlite3LogEst(nOut);
-        pNew->nOut = MIN(nOut, saved_nOut);
-      }
+      assert( nOut==pNew->nOut || rc==SQLITE_OK );
+      if( nOut<pNew->nOut ) pNew->nOut = nOut;
     }
 #endif
     if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
@@ -4460,7 +4460,7 @@ static int whereLoopAddBtree(
   WhereInfo *pWInfo;          /* WHERE analysis context */
   Index *pProbe;              /* An index we are evaluating */
   Index sPk;                  /* A fake index object for the primary key */
-  tRowcnt aiRowEstPk[2];      /* The aiRowEst[] value for the sPk index */
+  LogEst aiRowEstPk[2];       /* The aiRowEst[] value for the sPk index */
   int aiColumnPk = -1;        /* The aColumn[] value for the sPk index */
   SrcList *pTabList;          /* The FROM clause */
   struct SrcList_item *pSrc;  /* The FROM clause btree term to add */
@@ -4495,7 +4495,7 @@ static int whereLoopAddBtree(
     sPk.onError = OE_Replace;
     sPk.pTable = pSrc->pTab;
     aiRowEstPk[0] = pSrc->pTab->nRowEst;
-    aiRowEstPk[1] = 1;
+    aiRowEstPk[1] = 0;
     pFirst = pSrc->pTab->pIndex;
     if( pSrc->notIndexed==0 ){
       /* The real indices of the table are only considered if the
@@ -4504,7 +4504,7 @@ static int whereLoopAddBtree(
     }
     pProbe = &sPk;
   }
-  rSize = sqlite3LogEst(pSrc->pTab->nRowEst);
+  rSize = pSrc->pTab->nRowEst;
   rLogSize = estLog(rSize);
 
 #ifndef SQLITE_OMIT_AUTOMATIC_INDEX