-C Better\scomments.\s\sSlight\stuning\sof\sparameters.
-D 2023-12-31T20:04:32.564
+C Omit\sthe\suneven=N\sargument\sin\ssqlite_stat1\sand\sreplace\sit\swith\svar=N1,N2,...\nso\sthat\sthe\svariation\sin\seach\scolumn\sis\sreported\sseparately.\s\sOmit\sthe\s"slow"\nargument\sfrom\ssqlite_stat1,\scomputing\sthat\sflag\sinternally.\s\sPRAGMA\sstats\sis\nenhanced\swith\sa\snew\scolumn\s"est"\sthat\sshows\sthe\saiRowLogEst\sarray\sfor\seach\nindex\safter\sit\shas\sbeen\smodified\sby\s"var=..."\sand\salso\sthe\s"slow"\sflag.
+D 2024-01-01T14:13:59.212
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F sqlite_cfg.h.in baf2e409c63d4e7a765e17769b6ff17c5a82bbd9cbf1e284fd2e4cefaff3fcf2
F src/alter.c 30c2333b8bb3af71e4eb9adeadee8aa20edb15917ed44b8422e5cd15f3dfcddc
-F src/analyze.c 47711a594b1e9784164d32715725f01bdb9fed52fd6cfaa2432730e8c3c2b746
+F src/analyze.c 15eef780c7263f1f5a6b00bc6f2c92a4ac5261b7be95e6ef00263d6c461a5e87
F src/attach.c cc9d00d30da916ff656038211410ccf04ed784b7564639b9b61d1839ed69fd39
F src/auth.c 19b7ccacae3dfba23fc6f1d0af68134fa216e9040e53b0681b4715445ea030b4
F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523
F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
-F src/pragma.c b5b4cff830575e6188cd56a295a57448d2b9dbc53f0dae58e22b97354cda3781
-F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
+F src/pragma.c 4b33fdfd0198481f74fa52c91c4583631fbec41615c989fd0fcc51204d9a8450
+F src/pragma.h f95996cd3ab16a1b04b59a70df92d7e4ced1dfd70f18553bb639838d4208b31e
F src/prepare.c 371f6115cb69286ebc12c6f2d7511279c2e47d9f54f475d46a554d687a3b312c
F src/printf.c 18fbdf028345c8fbe6044f5f5bfda5a10d48d6287afef088cc21b0ca57985640
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
F tool/mkopcodec.tcl 33d20791e191df43209b77d37f0ff0904620b28465cca6990cf8d60da61a07ef
F tool/mkopcodeh.tcl 769d9e6a8b462323150dc13a8539d6064664b72974f7894befe2491cc73e05cd
F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa
-F tool/mkpragmatab.tcl 32e359ccb21011958a821955254bd7a5fa7915d01a8c16fed91ffc8b40cb4adf
+F tool/mkpragmatab.tcl d014814d2a03f9191d00182c2fb5652f20b3744433eafed128b5192877f310ee
F tool/mkshellc.tcl b7adf08b82de60811d2cb6af05ff59fc17e5cd6f3e98743c14eaaa3f8971fed0
F tool/mksourceid.c 36aa8020014aed0836fd13c51d6dc9219b0df1761d6b5f58ff5b616211b079b9
F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P c216921b115169ebfd239267b4ab5ad0fc960ffadce09044b68812f49110d607
-R df3f6be38a64508c745873953ba288dd
+P 1cc32eccda8d126264c644df72e308e25c1e41cf4fb68c2f1b6d6d98cbc23ca5
+R 19a9761f2b89c57ab0cba5358f19e101
U drh
-Z 151bd3600feff84e5eb2b344bddccb6f
+Z 02e04e5291abe3d83162489e3488139a
# Remove this line to create a well-formed Fossil manifest.
-1cc32eccda8d126264c644df72e308e25c1e41cf4fb68c2f1b6d6d98cbc23ca5
\ No newline at end of file
+4a8fc17365ccd989cc8050179ac586ca246698c71a64d7209786fb5569ba583a
\ No newline at end of file
*/
sqlite3_str sStat; /* Text of the constructed "stat" line */
int i; /* Loop counter */
- int iUneven = 1; /* max/avg */
+ int bUneven = 0; /* True if the uneven=... argument is needed */
u64 nRow; /* Number of rows in the index */
sqlite3StrAccumInit(&sStat, 0, 0, 0, (p->nKeyCol+1)*100);
** estimated number of rows in the index. */
iVal = p->nEst;
}else if( iVal<mx/10 ){
- /* ^^-- TUNING: threshold for when uneven=NNN is reported
- ** tag-20231231-01: Report uneven= if the maximum run of identical
- ** values ever reaches or exceeds 10 (or so) times the average run.
+ /* ^^-- TUNING: threshold for when var=... is reported.
+ ** tag-20231231-01: Report var=... if the maximum run of identical
+ ** values ever reaches or exceeds 10 (or so) times the average run
+ ** for any column of the index.
+ **
** The reporting threshold of 10 is tunable, but if changed, one
** should also consider changing the aiRowLogEst adjustment factor at
** tag-20231231-02.
*/
- int iRatio = mx/iVal;
- if( iUneven<iRatio ) iUneven = iRatio;
+ bUneven = 1;
}else if( iVal==2 && p->nRow*10 <= nDistinct*11 ){
/* If the value is less than or equal to 1.1, round it down to 1.0 */
iVal = 1;
sqlite3_str_appendf(&sStat, " %llu", iVal);
assert( p->current.anEq[i] );
- /* Add the "slow" argument if the peak number of rows obtained
- ** from a full equality match is so large that a full table scan
- ** seems likely to be faster than using the index. The query planner
- ** will use the "slow" argument as a hint to avoid using this index
- ** for equality lookups.
- **
- ** We let ANALYZE determine "slow" rather than the query planner for
- ** two reasons: (1) It leaves a visible trace in the sqlite_stat1 table
- ** that an index is not useful, and hence serves as a hint to the
- ** application developers that the index is a good candidate to be
- ** dropped. (2) Being able to use UPDATE to control the presence or
- ** absence of the "slow" argument in sqlite_stat1 enables greater
- ** control over the query planner during testing.
- */
- if( i==p->nKeyCol-1
- && nRow > 1000 && nRow <= iVal*iUneven + sqlite3LogEst(nRow) - 6
- /* ^^^^------------- TUNING ----------------------------^ */
- ){
- sqlite3_str_appendf(&sStat, " slow");
- }
}
- if( iUneven>1 ){
- sqlite3_str_appendf(&sStat, " uneven=%d", iUneven);
+ if( bUneven ){
+ char cSep = '=';
+ sqlite3_str_appendf(&sStat, " var");
+ for(i=0; i<p->nKeyCol; i++){
+ u64 nDistinct = p->current.anDLt[i] + 1;
+ u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
+ u64 mx = p->current.amxEq[i];
+ int iRatio = mx/iVal;
+ sqlite3_str_appendf(&sStat, "%c%d", cSep, iRatio);
+ cSep = ',';
+ }
}
sqlite3ResultStrAccum(context, &sStat);
}
pIndex->szIdxRow = sqlite3LogEst(sz);
}else if( sqlite3_strglob("noskipscan*", z)==0 ){
pIndex->noSkipScan = 1;
- }else if( sqlite3_strglob("slow*", z)==0 ){
- pIndex->bSlow = 1;
- }else if( sqlite3_strglob("uneven=[0-9]*", z)==0 ){
- /* An argument of "uneven=NNN" means that the maximum length
- ** run of the same value is NNN times longer than the average.
- ** Go through the iaRowLogEst[] values for the index and increase
- ** them by 0.1*NNN, so that so that they are each about 1/10th of
- ** of the maximum value.
+ }else if( sqlite3_strglob("var=[0-9]*", z)==0 ){
+ /* An argument like "var=N1,N2,...NN" means that the maximum length
+ ** run of the same value is Nx times longer than the average for
+ ** the X-th column of the index.
**
- ** The stat column continues to hold the average run length, and
- ** then the average is adjusted by the uneven=NNN value. We do this
- ** instead of adjusting the run length values in the main body of
- ** the stat column for backwards compatibility to older versions of
- ** SQLite that expect values in state to be the true the average.
- ** Also because the file format specifies that the values in the main
- ** body of the stat column should be the true average.
+ ** For this implementation, go through the iaRowLogEst[] array and
+ ** increase each value by 1/10th of the average value, to account
+ ** for the variability of the estimate.
**
- ** tag-20231231-02: The 1/10th threshold is tunable. But if changed,
- ** one should make a similar adjustment to the uneven=NNN threashold
- ** at tag-20231231-01: TUNING ----vv */
- LogEst scale = sqlite3LogEst(sqlite3Atoi(z+7)) - 33;
- assert( sqlite3LogEst(10)==33 );
- if( scale>0 ){
- LogEst mx = aLog[0];
- int jj;
- for(jj=1; jj<pIndex->nKeyCol; jj++){
- LogEst x = aLog[jj] + scale;
- if( x>mx ) x = mx;
- aLog[jj] = x;
+ ** tag-20231231-02: The 1/10th value is tunable. See the tuning
+ ** comment in the body of the loop. The ANALYZE command only
+ ** inserts a var=... argument if one or more of the Nx values is
+ ** within the tuning range, so if changing the tuning factor here,
+ ** consider also changing it at tag-20232131-01.
+ **
+ ** The stat column continue to hold the average run length for the
+ ** initial integers, for backwards compatibility.
+ */
+ int jj = 1;
+ int kk = 4;
+ LogEst mx = aLog[0];
+ while( sqlite3Isdigit(z[kk]) ){
+ u64 v = z[kk++] - '0';
+ LogEst scale;
+ while( sqlite3Isdigit(z[kk]) ){ v = v*10 + z[kk++]-'0'; }
+ scale = sqlite3LogEst(v);
+ if( scale>33 ){
+ /* ^^----- TUNING --------------vv See tag 20231231-02 */
+ LogEst adjusted = aLog[jj] + scale - 33;
+ if( adjusted>mx ) adjusted = mx;
+ aLog[jj] = adjusted;
}
+ if( jj==pIndex->nKeyCol ) break;
+ if( z[kk]==',' ) kk++;
+ jj++;
}
}
#ifdef SQLITE_ENABLE_COSTMULT
while( z[0]!=0 && z[0]!=' ' ) z++;
while( z[0]==' ' ) z++;
}
+
+ /* Set the bSlow flag if the peak number of rows obtained
+ ** from a full equality match is so large that a full table scan
+ ** seems likely to be faster than using the index.
+ */
+ if( aLog[0] > 66 /* Index has more than 100 rows */
+ && aLog[0] <= aLog[pIndex->nKeyCol] /* And only a single value seen */
+ ){
+ pIndex->bSlow = 1;
+ }
}
}
break;
#ifdef SQLITE_DEBUG
+ /* The output of this pragma is undocumented in the official documentation
+ ** because it is subject to change, and we don't want people coming to
+ ** rely on it.
+ **
+ ** Columns:
+ ** tbl Name of a table that is being described
+ ** idx Name of an index (belonging to tbl) being described
+ ** wdth LogEst of the on-disk estimated bytes per row
+ ** hght LogEst of the estimated number of rows
+ ** flgs tabFlags for tables
+ ** est aiRowLogEst[] values for indexes + "slow" flag
+ */
case PragTyp_STATS: {
Index *pIdx;
HashElem *i;
- pParse->nMem = 5;
+ sqlite3_str est;
+ sqlite3StrAccumInit(&est, 0, 0, 0, SQLITE_MAX_LENGTH);
+ pParse->nMem = 6;
sqlite3CodeVerifySchema(pParse, iDb);
for(i=sqliteHashFirst(&pDb->pSchema->tblHash); i; i=sqliteHashNext(i)){
Table *pTab = sqliteHashData(i);
- sqlite3VdbeMultiLoad(v, 1, "ssiii",
+ sqlite3VdbeMultiLoad(v, 1, "ssiiis",
sqlite3PreferredTableName(pTab->zName),
0,
pTab->szTabRow,
pTab->nRowLogEst,
- pTab->tabFlags);
+ pTab->tabFlags,
+ 0);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
- sqlite3VdbeMultiLoad(v, 2, "siiiX",
+ int j;
+ est.nChar = 0;
+ for(j=1; j<pIdx->nKeyCol+1; j++){
+ if( j>1 ) sqlite3_str_append(&est, " ", 1);
+ sqlite3_str_appendf(&est, "%d", pIdx->aiRowLogEst[j]);
+ }
+ if( pIdx->bSlow ) sqlite3_str_append(&est, " slow", 5);
+ sqlite3VdbeMultiLoad(v, 2, "siiisX",
pIdx->zName,
pIdx->szIdxRow,
pIdx->aiRowLogEst[0],
- pIdx->hasStat1);
- sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 5);
+ pIdx->hasStat1,
+ sqlite3_str_value(&est));
+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 6);
+ sqlite3_str_reset(&est);
}
}
}
/* 18 */ "ncol",
/* 19 */ "wr",
/* 20 */ "strict",
- /* 21 */ "seqno", /* Used by: index_xinfo */
- /* 22 */ "cid",
- /* 23 */ "name",
- /* 24 */ "desc",
- /* 25 */ "coll",
- /* 26 */ "key",
- /* 27 */ "name", /* Used by: function_list */
- /* 28 */ "builtin",
- /* 29 */ "type",
- /* 30 */ "enc",
- /* 31 */ "narg",
- /* 32 */ "flags",
- /* 33 */ "tbl", /* Used by: stats */
- /* 34 */ "idx",
- /* 35 */ "wdth",
- /* 36 */ "hght",
- /* 37 */ "flgs",
- /* 38 */ "seq", /* Used by: index_list */
- /* 39 */ "name",
- /* 40 */ "unique",
- /* 41 */ "origin",
- /* 42 */ "partial",
- /* 43 */ "table", /* Used by: foreign_key_check */
- /* 44 */ "rowid",
- /* 45 */ "parent",
- /* 46 */ "fkid",
- /* index_info reuses 21 */
- /* 47 */ "seq", /* Used by: database_list */
- /* 48 */ "name",
- /* 49 */ "file",
- /* 50 */ "busy", /* Used by: wal_checkpoint */
- /* 51 */ "log",
- /* 52 */ "checkpointed",
- /* collation_list reuses 38 */
- /* 53 */ "database", /* Used by: lock_status */
- /* 54 */ "status",
- /* 55 */ "cache_size", /* Used by: default_cache_size */
+ /* 21 */ "tbl", /* Used by: stats */
+ /* 22 */ "idx",
+ /* 23 */ "wdth",
+ /* 24 */ "hght",
+ /* 25 */ "flgs",
+ /* 26 */ "est",
+ /* 27 */ "seqno", /* Used by: index_xinfo */
+ /* 28 */ "cid",
+ /* 29 */ "name",
+ /* 30 */ "desc",
+ /* 31 */ "coll",
+ /* 32 */ "key",
+ /* 33 */ "name", /* Used by: function_list */
+ /* 34 */ "builtin",
+ /* 35 */ "type",
+ /* 36 */ "enc",
+ /* 37 */ "narg",
+ /* 38 */ "flags",
+ /* 39 */ "seq", /* Used by: index_list */
+ /* 40 */ "name",
+ /* 41 */ "unique",
+ /* 42 */ "origin",
+ /* 43 */ "partial",
+ /* 44 */ "table", /* Used by: foreign_key_check */
+ /* 45 */ "rowid",
+ /* 46 */ "parent",
+ /* 47 */ "fkid",
+ /* index_info reuses 27 */
+ /* 48 */ "seq", /* Used by: database_list */
+ /* 49 */ "name",
+ /* 50 */ "file",
+ /* 51 */ "busy", /* Used by: wal_checkpoint */
+ /* 52 */ "log",
+ /* 53 */ "checkpointed",
+ /* collation_list reuses 39 */
+ /* 54 */ "database", /* Used by: lock_status */
+ /* 55 */ "status",
+ /* 56 */ "cache_size", /* Used by: default_cache_size */
/* module_list pragma_list reuses 9 */
- /* 56 */ "timeout", /* Used by: busy_timeout */
+ /* 57 */ "timeout", /* Used by: busy_timeout */
};
/* Definitions of all built-in pragmas */
{/* zName: */ "busy_timeout",
/* ePragTyp: */ PragTyp_BUSY_TIMEOUT,
/* ePragFlg: */ PragFlg_Result0,
- /* ColNames: */ 56, 1,
+ /* ColNames: */ 57, 1,
/* iArg: */ 0 },
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{/* zName: */ "cache_size",
{/* zName: */ "collation_list",
/* ePragTyp: */ PragTyp_COLLATION_LIST,
/* ePragFlg: */ PragFlg_Result0,
- /* ColNames: */ 38, 2,
+ /* ColNames: */ 39, 2,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS)
{/* zName: */ "database_list",
/* ePragTyp: */ PragTyp_DATABASE_LIST,
/* ePragFlg: */ PragFlg_Result0,
- /* ColNames: */ 47, 3,
+ /* ColNames: */ 48, 3,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
{/* zName: */ "default_cache_size",
/* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1,
- /* ColNames: */ 55, 1,
+ /* ColNames: */ 56, 1,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
{/* zName: */ "foreign_key_check",
/* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_Result1|PragFlg_SchemaOpt,
- /* ColNames: */ 43, 4,
+ /* ColNames: */ 44, 4,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FOREIGN_KEY)
{/* zName: */ "function_list",
/* ePragTyp: */ PragTyp_FUNCTION_LIST,
/* ePragFlg: */ PragFlg_Result0,
- /* ColNames: */ 27, 6,
+ /* ColNames: */ 33, 6,
/* iArg: */ 0 },
#endif
#endif
{/* zName: */ "index_info",
/* ePragTyp: */ PragTyp_INDEX_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
- /* ColNames: */ 21, 3,
+ /* ColNames: */ 27, 3,
/* iArg: */ 0 },
{/* zName: */ "index_list",
/* ePragTyp: */ PragTyp_INDEX_LIST,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
- /* ColNames: */ 38, 5,
+ /* ColNames: */ 39, 5,
/* iArg: */ 0 },
{/* zName: */ "index_xinfo",
/* ePragTyp: */ PragTyp_INDEX_INFO,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt,
- /* ColNames: */ 21, 6,
+ /* ColNames: */ 27, 6,
/* iArg: */ 1 },
#endif
#if !defined(SQLITE_OMIT_INTEGRITY_CHECK)
{/* zName: */ "lock_status",
/* ePragTyp: */ PragTyp_LOCK_STATUS,
/* ePragFlg: */ PragFlg_Result0,
- /* ColNames: */ 53, 2,
+ /* ColNames: */ 54, 2,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{/* zName: */ "stats",
/* ePragTyp: */ PragTyp_STATS,
/* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq,
- /* ColNames: */ 33, 5,
+ /* ColNames: */ 21, 6,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS)
{/* zName: */ "wal_checkpoint",
/* ePragTyp: */ PragTyp_WAL_CHECKPOINT,
/* ePragFlg: */ PragFlg_NeedSchema,
- /* ColNames: */ 50, 3,
+ /* ColNames: */ 51, 3,
/* iArg: */ 0 },
#endif
#if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
NAME: stats
FLAG: NeedSchema Result0 SchemaReq
- COLS: tbl idx wdth hght flgs
+ COLS: tbl idx wdth hght flgs est
IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) && defined(SQLITE_DEBUG)
NAME: index_info