From 518140ed049bc2a6c5892e0c54d5cf7b11ed660a Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 6 Nov 2014 03:55:10 +0000 Subject: [PATCH] Change the SQLITE_SCANSTAT_EST parameter so that it returns a double for the estimated number of output rows per loop, rather than a 64-bit integer. Revise the output format for the ".scanstats on" in the shell to make use of this new capability. FossilOrigin-Name: f9684000665ae7ef6f89c3773612b8286b8f545a --- manifest | 32 ++++++++++--------- manifest.uuid | 2 +- src/shell.c | 13 +++++--- src/sqlite.h.in | 12 ++++--- src/test1.c | 6 ++-- src/vdbe.h | 2 +- src/vdbeInt.h | 2 +- src/vdbeapi.c | 8 ++++- src/vdbeaux.c | 2 +- src/where.c | 6 +--- test/scanstatus.test | 76 ++++++++++++++++++++++---------------------- 11 files changed, 85 insertions(+), 76 deletions(-) diff --git a/manifest b/manifest index a8453434a2..75d37178fb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fixes\sto\sthe\sWindows\sVFS\sto\sallow\smemory\smapped\sfiles\sto\swork\swithout\sWAL\ssupport. -D 2014-11-05T21:34:56.096 +C Change\sthe\sSQLITE_SCANSTAT_EST\sparameter\sso\sthat\sit\sreturns\sa\sdouble\sfor\nthe\sestimated\snumber\sof\soutput\srows\sper\sloop,\srather\sthan\sa\s64-bit\sinteger.\nRevise\sthe\soutput\sformat\sfor\sthe\s".scanstats\son"\sin\sthe\sshell\sto\smake\suse\nof\sthis\snew\scapability. +D 2014-11-06T03:55:10.745 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -228,8 +228,8 @@ F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 428165951748151e87a15295b7357221433e311b -F src/shell.c 5ad1eb4dfcd7a57e15825207a9bd559415bf34b1 -F src/sqlite.h.in 6e9af739d79f0bea2584b70fb1c54d3bb1a2eab6 +F src/shell.c 908ff96ef1551b28b940aaf4c886ba2681057209 +F src/sqlite.h.in e13a7b64efa8d6a591577e6a5281fb22783c0133 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761 @@ -237,7 +237,7 @@ F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 81712116e826b0089bb221b018929536b2b5406f F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc F src/tclsqlite.c 7cdd4dd3c2a4183483feca260070d73d6e22cd47 -F src/test1.c 5890094c09691fe9564cf0f0d5b22d35b3218c47 +F src/test1.c ac7f3bad83ef4508d5efc85b32e86da48db8ed7e F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -290,10 +290,10 @@ F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73 F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a F src/vdbe.c 3fd4ebd3e87b63175bfd2be747608bae1670b4df -F src/vdbe.h d412bd01e89f0d69991b8f46601f96bc169d28f4 -F src/vdbeInt.h 539ba284790e871f98be74a78cbdfcedfae22639 -F src/vdbeapi.c 900259bdd85cd66a9f210d8ec08147a9034593bd -F src/vdbeaux.c cf6b8152dd22155201d57c216e6266866b61da59 +F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3 +F src/vdbeInt.h c32c1de25e3821a5b53d73abdb23ccc644ec5b63 +F src/vdbeapi.c 6a126fd8ed297ff0542bfbf7891b92977b5ed653 +F src/vdbeaux.c 9b0a251b6dfab349dd6c6efb40062eb7386b26f5 F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f F src/vdbesort.c 87f3923483113d1c95d84640becb4e4946f27d9a @@ -302,7 +302,7 @@ F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793 F src/wal.c 825c948066c7604a07d56e67958cdab210749016 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 2c2081c546c90227577c502765611555503ce3f7 +F src/where.c 3862a1173ae2716bde12f1ab3fb649f1d85b05c2 F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -801,7 +801,7 @@ F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0 F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7 F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423 -F test/scanstatus.test 01afb2220f18ce85f9e338c20684f428d56e5c01 +F test/scanstatus.test a6dd739bc4d9638e8f5c2493b518057f2b681655 F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481 F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5 F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38 @@ -1211,8 +1211,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 83a1e5db926b3a6d40f4a5cf9a8e6852b9bac9ac 6fc4ead26d19b9348bbda34c3053ae1e066abc32 -R 3ad47b2ac5693ba63ff5c591cf540d89 -T +closed 6fc4ead26d19b9348bbda34c3053ae1e066abc32 +P 272fddc14cc322655eeba670bc0f9fc30e5a804c +R c0f850c2227a7a137fbc73d5c1c5136e +T *branch * scanstatus +T *sym-scanstatus * +T -sym-trunk * U drh -Z ee3b32335a4c8630acaf81919b28b64e +Z f39cd1607e4aacbb491c044bd0bb317e diff --git a/manifest.uuid b/manifest.uuid index b558f09274..d125168b7d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -272fddc14cc322655eeba670bc0f9fc30e5a804c \ No newline at end of file +f9684000665ae7ef6f89c3773612b8286b8f545a \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index 3423bb0143..4dd0ffa1a1 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1195,21 +1195,24 @@ static void display_scanstats( ){ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int i; + double rEstLoop = 1.0; fprintf(pArg->out, "-------- scanstats --------\n"); for(i=0; 1; i++){ sqlite3_stmt *p = pArg->pStmt; - sqlite3_int64 nEst, nLoop, nVisit; + sqlite3_int64 nLoop, nVisit; + double rEst; const char *zExplain; if( sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop) ){ break; } sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); - sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&nEst); + sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EST, (void*)&rEst); sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain); - fprintf(pArg->out, "Loop %d: \"%s\"\n", i, zExplain); - fprintf(pArg->out, " nLoop=%-8lld nVisit=%-8lld nEst=%-8lld\n", - nLoop, nVisit, nEst + fprintf(pArg->out, "Loop %2d: \"%s\"\n", i, zExplain); + rEstLoop *= rEst; + fprintf(pArg->out, " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n", + nLoop, nVisit, (sqlite3_int64)rEstLoop, rEst ); } #else diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 44f7800ca2..c309dc1c5b 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -7440,13 +7440,15 @@ int sqlite3_vtab_on_conflict(sqlite3 *); ** ** [[SQLITE_SCANSTAT_NVISIT]]
SQLITE_SCANSTAT_NVISIT
**
^The [sqlite3_int64] variable pointed to by the T parameter will be set to the -** total number of rows visited by the X-th loop.
+** total number of rows examined by all iterations of the X-th loop. ** ** [[SQLITE_SCANSTAT_EST]]
SQLITE_SCANSTAT_EST
-**
^The [sqlite3_int64] variable pointed to by the T parameter will be set to the -** query planner's estimate for the number of rows visited for each -** iteration of the X-th loop. If the query planner's estimate was accurate, -** then this value should be approximately NVISIT/NLOOP. +**
^The "double" variable pointed to by the T parameter will be set to the +** query planner's estimate for the average number of rows output from each +** iteration of the X-th loop. If the query planner's estimates was accurate, +** then this value will approximate the quotient NVISIT/NLOOP and the +** product of this value for the first N-1 loops will approximate +** the NLOOP value for the N-th loop. ** ** [[SQLITE_SCANSTAT_NAME]]
SQLITE_SCANSTAT_NAME
**
^The "const char *" variable pointed to by the T parameter will be set to diff --git a/src/test1.c b/src/test1.c index 5e526b3013..fcc1a23de1 100644 --- a/src/test1.c +++ b/src/test1.c @@ -2318,7 +2318,7 @@ static int test_stmt_scanstatus( const char *zExplain; sqlite3_int64 nLoop; sqlite3_int64 nVisit; - sqlite3_int64 nEst; + double rEst; int res; if( objc!=3 ){ @@ -2336,9 +2336,9 @@ static int test_stmt_scanstatus( sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nVisit", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nVisit)); - sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EST, (void*)&nEst); + sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EST, (void*)&rEst); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nEst", -1)); - Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nEst)); + Tcl_ListObjAppendElement(0, pRet, Tcl_NewDoubleObj(rEst)); sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NAME, (void*)&zName); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zName", -1)); Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zName, -1)); diff --git a/src/vdbe.h b/src/vdbe.h index 1b9ad8b6bf..b715241b41 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -283,7 +283,7 @@ void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *); #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS -void sqlite3VdbeScanStatus(Vdbe*, int, int, int, i64, const char*); +void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*); #else # define sqlite3VdbeScanStatus(a,b,c,d,e) #endif diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 29117dd064..a42ca3dffc 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -302,7 +302,7 @@ struct ScanStatus { int addrExplain; /* OP_Explain for loop */ int addrLoop; /* Address of "loops" counter */ int addrVisit; /* Address of "rows visited" counter */ - i64 nEst; /* Estimated rows per loop */ + LogEst nEst; /* Estimated output rows per loop */ char *zName; /* Name of table or index */ }; diff --git a/src/vdbeapi.c b/src/vdbeapi.c index d472004590..d907afee00 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1500,7 +1500,13 @@ int sqlite3_stmt_scanstatus( break; } case SQLITE_SCANSTAT_EST: { - *(sqlite3_int64*)pOut = pScan->nEst; + double r = 1.0; + LogEst x = pScan->nEst; + while( x<100 ){ + x += 10; + r *= 0.5; + } + *(double*)pOut = r*sqlite3LogEstToInt(x); break; } case SQLITE_SCANSTAT_NAME: { diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 7cf996ce5c..d8ee5c8e8c 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -606,7 +606,7 @@ void sqlite3VdbeScanStatus( int addrExplain, /* Address of OP_Explain (or 0) */ int addrLoop, /* Address of loop counter */ int addrVisit, /* Address of rows visited counter */ - i64 nEst, /* Estimated number of rows */ + LogEst nEst, /* Estimated number of output rows */ const char *zName /* Name of table or index being scanned */ ){ int nByte = (p->nScan+1) * sizeof(ScanStatus); diff --git a/src/where.c b/src/where.c index 92f783b2e9..c3641c7cc7 100644 --- a/src/where.c +++ b/src/where.c @@ -2946,18 +2946,14 @@ static void addScanStatus( int addrExplain /* Address of OP_Explain (or 0) */ ){ const char *zObj = 0; - i64 nEst = 1; WhereLoop *pLoop = pLvl->pWLoop; if( (pLoop->wsFlags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ zObj = pLoop->u.btree.pIndex->zName; }else{ zObj = pSrclist->a[pLvl->iFrom].zName; } - if( pLoop->nOut>=10 ){ - nEst = sqlite3LogEstToInt(pLoop->nOut); - } sqlite3VdbeScanStatus( - v, addrExplain, pLvl->addrBody, pLvl->addrVisit, nEst, zObj + v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj ); } #else diff --git a/test/scanstatus.test b/test/scanstatus.test index 9b34506e91..7713bae5fc 100644 --- a/test/scanstatus.test +++ b/test/scanstatus.test @@ -45,8 +45,8 @@ proc do_scanstatus_test {tn res} { do_execsql_test 1.1 { SELECT count(*) FROM t1, t2; } 6 do_scanstatus_test 1.2 { - nLoop 1 nVisit 2 nEst 1048576 zName t1 zExplain {SCAN TABLE t1} - nLoop 2 nVisit 6 nEst 1048576 zName t2 zExplain {SCAN TABLE t2} + nLoop 1 nVisit 2 nEst 1048576.0 zName t1 zExplain {SCAN TABLE t1} + nLoop 2 nVisit 6 nEst 1048576.0 zName t2 zExplain {SCAN TABLE t2} } do_execsql_test 1.3 { @@ -54,8 +54,8 @@ do_execsql_test 1.3 { SELECT count(*) FROM t1, t2; } 6 do_scanstatus_test 1.4 { - nLoop 1 nVisit 2 nEst 2 zName t1 zExplain {SCAN TABLE t1} - nLoop 2 nVisit 6 nEst 3 zName t2 zExplain {SCAN TABLE t2} + nLoop 1 nVisit 2 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} + nLoop 2 nVisit 6 nEst 3.0 zName t2 zExplain {SCAN TABLE t2} } do_execsql_test 1.5 { ANALYZE } @@ -63,9 +63,9 @@ do_execsql_test 1.6 { SELECT count(*) FROM t1, t2 WHERE t2.rowid>1; } 4 do_scanstatus_test 1.7 { - nLoop 1 nVisit 2 nEst 2 zName t2 zExplain + nLoop 1 nVisit 2 nEst 2.0 zName t2 zExplain {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} - nLoop 2 nVisit 4 nEst 2 zName t1 zExplain {SCAN TABLE t1} + nLoop 2 nVisit 4 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} } do_execsql_test 1.8 { @@ -73,9 +73,9 @@ do_execsql_test 1.8 { } 4 do_scanstatus_test 1.9 { - nLoop 2 nVisit 4 nEst 2 zName t2 zExplain + nLoop 2 nVisit 4 nEst 2.0 zName t2 zExplain {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} - nLoop 4 nVisit 8 nEst 2 zName t1 zExplain {SCAN TABLE t1} + nLoop 4 nVisit 8 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} } do_test 1.9 { @@ -83,9 +83,9 @@ do_test 1.9 { } {} do_scanstatus_test 1.10 { - nLoop 0 nVisit 0 nEst 2 zName t2 zExplain + nLoop 0 nVisit 0 nEst 2.0 zName t2 zExplain {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid>?)} - nLoop 0 nVisit 0 nEst 2 zName t1 zExplain {SCAN TABLE t1} + nLoop 0 nVisit 0 nEst 2.0 zName t1 zExplain {SCAN TABLE t1} } #------------------------------------------------------------------------- @@ -104,7 +104,7 @@ do_execsql_test 2.1 { } {2 two} do_scanstatus_test 2.2 { - nLoop 1 nVisit 1 nEst 1 zName x1 + nLoop 1 nVisit 1 nEst 1.0 zName x1 zExplain {SEARCH TABLE x1 USING INTEGER PRIMARY KEY (rowid=?)} } @@ -112,7 +112,7 @@ do_execsql_test 2.3.1 { SELECT * FROM x1 WHERE j='two' } {2 two} do_scanstatus_test 2.3.2 { - nLoop 1 nVisit 1 nEst 10 zName x1j + nLoop 1 nVisit 1 nEst 10.0 zName x1j zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j=?)} } @@ -120,7 +120,7 @@ do_execsql_test 2.4.1 { SELECT * FROM x1 WHERE j<'two' } {4 four 1 one 3 three} do_scanstatus_test 2.4.2 { - nLoop 1 nVisit 3 nEst 262144 zName x1j + nLoop 1 nVisit 3 nEst 262144.0 zName x1j zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j='two' } {2 two} do_scanstatus_test 2.5.2 { - nLoop 1 nVisit 1 nEst 262144 zName x1j + nLoop 1 nVisit 1 nEst 262144.0 zName x1j zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>?)} } @@ -136,7 +136,7 @@ do_execsql_test 2.6.1 { SELECT * FROM x1 WHERE j BETWEEN 'three' AND 'two' } {3 three 2 two} do_scanstatus_test 2.6.2 { - nLoop 1 nVisit 2 nEst 16384 zName x1j + nLoop 1 nVisit 2 nEst 16384.0 zName x1j zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j>? AND j? AND j? AND a? AND b? AND b? AND a