From: drh Date: Tue, 25 Oct 2016 13:57:40 +0000 (+0000) Subject: First attempt at a utility program to compute sqlite_stat1 without doing X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5fba856bbf0245dce545fad8c3d40c33d5037fb0;p=thirdparty%2Fsqlite.git First attempt at a utility program to compute sqlite_stat1 without doing a full table scan. FossilOrigin-Name: 7b83581a43384fe81dc319482e03be0df45ab25d --- diff --git a/main.mk b/main.mk index a5a50d205d..118843e38d 100644 --- a/main.mk +++ b/main.mk @@ -497,6 +497,10 @@ dbhash$(EXE): $(TOP)/tool/dbhash.c sqlite3.c sqlite3.h $(TCCX) -o dbhash$(EXE) -DSQLITE_THREADSAFE=0 \ $(TOP)/tool/dbhash.c sqlite3.c $(TLIBS) $(THREADLIB) +faststat1$(EXE): $(TOP)/tool/faststat1.c sqlite3.c sqlite3.h + $(TCCX) -o faststat1$(EXE) -DSQLITE_THREADSAFE=0 \ + $(TOP)/tool/faststat1.c sqlite3.c $(TLIBS) $(THREADLIB) + scrub$(EXE): $(TOP)/ext/misc/scrub.c sqlite3.o $(TCC) -I. -DSCRUB_STANDALONE -o scrub$(EXE) $(TOP)/ext/misc/scrub.c sqlite3.o $(THREADLIB) diff --git a/manifest b/manifest index 624111029c..a38df93cf5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\sreading\sfrom\san\sindex,\sthe\sshared-cache\slock\smust\sbe\son\sthe\scorresponding\ntable. -D 2016-10-21T18:01:40.991 +C First\sattempt\sat\sa\sutility\sprogram\sto\scompute\ssqlite_stat1\swithout\sdoing\na\sfull\stable\sscan. +D 2016-10-25T13:57:40.551 F Makefile.in 6fd48ffcf7c2deea7499062d1f3747f986c19678 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 5151cc64c4c05f3455f4f692ad11410a810d937f @@ -311,7 +311,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 06dc0b1a9c9e2d05c9275937dd5b894bfe7d17d8 +F main.mk 1e4a0bdbe86b94b46df89e241949dc3156243f0f F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -1449,6 +1449,7 @@ F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2 F tool/dbhash.c a06228aa21ebc4e6ea8daa486601d938499238a5 F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2 F tool/fast_vacuum.c 5ba0d6f5963a0a63bdc42840f678bad75b2ebce1 +F tool/faststat1.c 2178e42e0206ac80a49834454e716cfc21060cfa F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439 F tool/fuzzershell.c f294ca67a10e87db76af130d75b2c94be36359c6 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 @@ -1527,7 +1528,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 0c8a5b8844df3389881aecd8e853eb3c78edd954 -R d660078687b657495181c871ccc08c5d +P 04fe12b590ab67e40cd079b5e614b787f5f525ad +R bd47d064e2ed9e25c0899a770a248208 U drh -Z 6dae85bfa44e07a1b59d3382cd897280 +Z d3e8fe3b1d555eec50042b333c79640e diff --git a/manifest.uuid b/manifest.uuid index 231aa71907..19d3391591 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -04fe12b590ab67e40cd079b5e614b787f5f525ad \ No newline at end of file +7b83581a43384fe81dc319482e03be0df45ab25d \ No newline at end of file diff --git a/tool/faststat1.c b/tool/faststat1.c new file mode 100644 index 0000000000..233cfd28a8 --- /dev/null +++ b/tool/faststat1.c @@ -0,0 +1,423 @@ +/* +** 2016-10-24 +** +** 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 is a utility program that uses the est_count and btree_sample +** pragmas to try to approximate the content of the sqlite_stat1 table +** without doing a full table scan. +** +** To compile, simply link against SQLite. +** +** See the showHelp() routine below for a brief description of how to +** run the utility. +*/ +#include +#include +#include +#include +#include +#include +#include "sqlite3.h" + +/* +** All global variables are gathered into the "g" singleton. +*/ +struct GlobalVars { + const char *zArgv0; /* Name of program */ + unsigned fDebug; /* Debug flags */ + sqlite3 *db; /* The database connection */ +} g; + +/* +** Allowed values for g.fDebug +*/ +#define DEBUG_NONE 0 + + +/* +** Print an error resulting from faulting command-line arguments and +** abort the program. +*/ +static void cmdlineError(const char *zFormat, ...){ + va_list ap; + fprintf(stderr, "%s: ", g.zArgv0); + va_start(ap, zFormat); + vfprintf(stderr, zFormat, ap); + va_end(ap); + fprintf(stderr, "\n\"%s --help\" for more help\n", g.zArgv0); + exit(1); +} + +/* +** Print an error message for an error that occurs at runtime, then +** abort the program. +*/ +static void runtimeError(const char *zFormat, ...){ + va_list ap; + fprintf(stderr, "%s: ", g.zArgv0); + va_start(ap, zFormat); + vfprintf(stderr, zFormat, ap); + va_end(ap); + fprintf(stderr, "\n"); + exit(1); +} + +/* +** Prepare a new SQL statement. Print an error and abort if anything +** goes wrong. +*/ +static sqlite3_stmt *db_vprepare(const char *zFormat, va_list ap){ + char *zSql; + int rc; + sqlite3_stmt *pStmt; + + zSql = sqlite3_vmprintf(zFormat, ap); + if( zSql==0 ) runtimeError("out of memory"); + rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0); + if( rc ){ + runtimeError("SQL statement error: %s\n\"%s\"", sqlite3_errmsg(g.db), + zSql); + } + sqlite3_free(zSql); + return pStmt; +} +static sqlite3_stmt *db_prepare(const char *zFormat, ...){ + va_list ap; + sqlite3_stmt *pStmt; + va_start(ap, zFormat); + pStmt = db_vprepare(zFormat, ap); + va_end(ap); + return pStmt; +} + +/* +** Estimate the number of rows in the given table or index. +*/ +static sqlite3_int64 estEntryCount(const char *zTabIdx){ + double sum = 0.0; + int i; + int n = 0; + sqlite3_stmt *pStmt; +# define N_CNT_SAMPLE 10 + for(i=0; i<=N_CNT_SAMPLE; i++){ + pStmt = db_prepare("PRAGMA est_count(\"%w\",%g)", + zTabIdx, ((double)i)/(double)(N_CNT_SAMPLE)); + if( sqlite3_step(pStmt)==SQLITE_ROW ){ + sum += sqlite3_column_double(pStmt, 0); + n++; + } + sqlite3_finalize(pStmt); + } + return n==0 ? 0 : (sqlite3_int64)(sum/n); +} + +/* +** Stat1 for a table. +*/ +static void analyzeTable(const char *zTab){ + sqlite3_int64 n = estEntryCount(zTab); + sqlite3_stmt *pStmt; + if( n==0 ){ + printf("-- empty table: %s\n", zTab); + return; + } + pStmt = db_prepare( + "INSERT INTO temp.est_stat1(tbl,idx,stat)" + "VALUES(\"%w\",NULL,'%lld')", zTab, n + ); + sqlite3_step(pStmt); + sqlite3_finalize(pStmt); +} + +/* +** Compare the i-th column of pStmt against pValue. Return true if they +** are different. +*/ +static int columnNotEqual(sqlite3_stmt *pStmt, int i, sqlite3_value *pValue){ + int n1, n2, n; + if( sqlite3_column_type(pStmt,i)!=sqlite3_value_type(pValue) ) return 1; + switch( sqlite3_column_type(pStmt,i) ){ + case SQLITE_NULL: + return 0; /* Nulls compare equal to one another in this context */ + + case SQLITE_INTEGER: + return sqlite3_column_int64(pStmt,i)!=sqlite3_value_int64(pValue); + + case SQLITE_FLOAT: + return sqlite3_column_double(pStmt,i)!=sqlite3_value_double(pValue); + + case SQLITE_BLOB: + n1 = sqlite3_column_bytes(pStmt,i); + n2 = sqlite3_value_bytes(pValue); + n = n110000 ? 100 : 20000; + pStmt = db_prepare("PRAGMA btree_sample(\"%w\",0.0,%lld)", + zIdx, n*2); + for(i=0; i0" + " AND (type='index' OR name NOT LIKE 'sqlite_%%')" + " ORDER BY tbl_name, type DESC, name"); + while( sqlite3_step(pStmt)==SQLITE_ROW ){ + const char *zType = (const char*)sqlite3_column_text(pStmt, 0); + const char *zName = (const char*)sqlite3_column_text(pStmt, 1); + const char *zTblName = (const char*)sqlite3_column_text(pStmt, 2); + if( zType[0]=='t' ){ + analyzeTable(zName); + }else{ + analyzeIndex(zTblName, zName); + } + } + sqlite3_finalize(pStmt); + dump_table("temp.est_stat1","sqlite_stat1"); + sqlite3_close(g.db); + return 0; +}