Merge the ANALYZE-index enhancement into trunk.

FossilOrigin-Name: 7e237aea22084416d02b89d5223de4e1ca76882d
This commit is contained in:
drh
2011-04-01 14:26:14 +00:00
4 changed files with 145 additions and 25 deletions
+7 -6
View File
@@ -1,5 +1,5 @@
C Move\sa\svariable\sdeclaration\sinside\san\s#ifdef\sto\savoid\sa\scompiler\swarning.
D 2011-04-01T13:29:29.578
C Merge\sthe\sANALYZE-index\senhancement\sinto\strunk.
D 2011-04-01T14:26:14.943
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -115,7 +115,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
F src/alter.c 6a0c176e64a34929a4436048066a84ef4f1445b3
F src/analyze.c 6b536214aece5100f4814b715b1a9f096193bf14
F src/analyze.c d0a673d303f611690fc7a3293aaefed57cccc5c8
F src/attach.c 438ea6f6b5d5961c1f49b737f2ce0f14ce7c6877
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c 537f89c7ef5021cb580f31f782e556ffffcb2ed1
@@ -259,6 +259,7 @@ F test/analyze3.test d61f55d8b472fc6e713160b1e577f7a68e63f38b
F test/analyze4.test 757b37875cf9bb528d46f74497bc789c88365045
F test/analyze5.test adc89b92fc9fee5ca1cb0bc8512f3206ad0fe5aa
F test/analyze6.test c125622a813325bba1b4999040ddc213773c2290
F test/analyze7.test 06405dd3d2a3101de14270da508016a59254873b
F test/async.test ad4ba51b77cd118911a3fe1356b0809da9c108c3
F test/async2.test bf5e2ca2c96763b4cba3d016249ad7259a5603b6
F test/async3.test 93edaa9122f498e56ea98c36c72abc407f4fb11e
@@ -920,7 +921,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P ff6dfe6ed74f9ff1669b2bda41d61a01cd0a1bc6
R d5791c0430fd039b1944fc050ba93b96
P 7a6d05dfbc36310683dd51a280e9283cef4f9056 365896cb0868fa476e3b4f5a965a1344a2914cc2
R 7c9526ecaff8bc8061319f5def8d1613
U drh
Z dde3d78a013928b388d93ef247b7695b
Z 1a31242492e35c93d42d83f1529d907f
+1 -1
View File
@@ -1 +1 @@
7a6d05dfbc36310683dd51a280e9283cef4f9056
7e237aea22084416d02b89d5223de4e1ca76882d
+31 -18
View File
@@ -34,7 +34,8 @@ static void openStatTable(
Parse *pParse, /* Parsing context */
int iDb, /* The database we are looking in */
int iStatCur, /* Open the sqlite_stat1 table on this cursor */
const char *zWhere /* Delete entries associated with this table */
const char *zWhere, /* Delete entries for this table or index */
const char *zWhereType /* Either "tbl" or "idx" */
){
static const struct {
const char *zName;
@@ -79,7 +80,7 @@ static void openStatTable(
sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab);
if( zWhere ){
sqlite3NestedParse(pParse,
"DELETE FROM %Q.%s WHERE tbl=%Q", pDb->zName, zTab, zWhere
"DELETE FROM %Q.%s WHERE %s=%Q", pDb->zName, zTab, zWhereType, zWhere
);
}else{
/* The sqlite_stat[12] table already exists. Delete all rows. */
@@ -103,6 +104,7 @@ static void openStatTable(
static void analyzeOneTable(
Parse *pParse, /* Parser context */
Table *pTab, /* Table whose indices are to be analyzed */
Index *pOnlyIdx, /* If not NULL, only analyze this one index */
int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */
int iMem /* Available memory locations begin here */
){
@@ -160,9 +162,12 @@ static void analyzeOneTable(
iIdxCur = pParse->nTab++;
sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0);
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int nCol = pIdx->nColumn;
KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
int nCol;
KeyInfo *pKey;
if( pOnlyIdx && pOnlyIdx!=pIdx ) continue;
nCol = pIdx->nColumn;
pKey = sqlite3IndexKeyinfo(pParse, pIdx);
if( iMem+1+(nCol*2)>pParse->nMem ){
pParse->nMem = iMem+1+(nCol*2);
}
@@ -383,20 +388,21 @@ static void analyzeDatabase(Parse *pParse, int iDb){
sqlite3BeginWriteOperation(pParse, 0, iDb);
iStatCur = pParse->nTab;
pParse->nTab += 2;
openStatTable(pParse, iDb, iStatCur, 0);
openStatTable(pParse, iDb, iStatCur, 0, 0);
iMem = pParse->nMem+1;
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k);
analyzeOneTable(pParse, pTab, iStatCur, iMem);
analyzeOneTable(pParse, pTab, 0, iStatCur, iMem);
}
loadAnalysis(pParse, iDb);
}
/*
** Generate code that will do an analysis of a single table in
** a database.
** a database. If pOnlyIdx is not NULL then it is a single index
** in pTab that should be analyzed.
*/
static void analyzeTable(Parse *pParse, Table *pTab){
static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){
int iDb;
int iStatCur;
@@ -406,8 +412,12 @@ static void analyzeTable(Parse *pParse, Table *pTab){
sqlite3BeginWriteOperation(pParse, 0, iDb);
iStatCur = pParse->nTab;
pParse->nTab += 2;
openStatTable(pParse, iDb, iStatCur, pTab->zName);
analyzeOneTable(pParse, pTab, iStatCur, pParse->nMem+1);
if( pOnlyIdx ){
openStatTable(pParse, iDb, iStatCur, pOnlyIdx->zName, "idx");
}else{
openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl");
}
analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur, pParse->nMem+1);
loadAnalysis(pParse, iDb);
}
@@ -429,6 +439,7 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
int i;
char *z, *zDb;
Table *pTab;
Index *pIdx;
Token *pTableName;
/* Read the database schema. If an error occurs, leave an error message
@@ -453,11 +464,12 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
}else{
z = sqlite3NameFromToken(db, pName1);
if( z ){
pTab = sqlite3LocateTable(pParse, 0, z, 0);
sqlite3DbFree(db, z);
if( pTab ){
analyzeTable(pParse, pTab);
if( (pIdx = sqlite3FindIndex(db, z, 0))!=0 ){
analyzeTable(pParse, pIdx->pTable, pIdx);
}else if( (pTab = sqlite3LocateTable(pParse, 0, z, 0))!=0 ){
analyzeTable(pParse, pTab, 0);
}
sqlite3DbFree(db, z);
}
}
}else{
@@ -467,11 +479,12 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
zDb = db->aDb[iDb].zName;
z = sqlite3NameFromToken(db, pTableName);
if( z ){
pTab = sqlite3LocateTable(pParse, 0, z, zDb);
sqlite3DbFree(db, z);
if( pTab ){
analyzeTable(pParse, pTab);
if( (pIdx = sqlite3FindIndex(db, z, zDb))!=0 ){
analyzeTable(pParse, pIdx->pTable, pIdx);
}else if( (pTab = sqlite3LocateTable(pParse, 0, z, zDb))!=0 ){
analyzeTable(pParse, pTab, 0);
}
sqlite3DbFree(db, z);
}
}
}
+106
View File
@@ -0,0 +1,106 @@
# 2011 April 1
#
# 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 file implements regression tests for SQLite library.
# This file implements tests for the ANALYZE command when an idnex
# name is given as the argument.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# There is nothing to test if ANALYZE is disable for this build.
#
ifcapable {!analyze} {
finish_test
return
}
# Generate some test data
#
do_test analyze7-1.0 {
execsql {
CREATE TABLE sequence(x INTEGER PRIMARY KEY);
INSERT INTO sequence VALUES(1);
INSERT INTO sequence VALUES(2);
INSERT INTO sequence SELECT x+2 FROM sequence;
INSERT INTO sequence SELECT x+4 FROM sequence;
INSERT INTO sequence SELECT x+8 FROM sequence;
INSERT INTO sequence SELECT x+16 FROM sequence;
INSERT INTO sequence SELECT x+32 FROM sequence;
INSERT INTO sequence SELECT x+64 FROM sequence;
INSERT INTO sequence SELECT x+128 FROM sequence;
INSERT INTO sequence SELECT x+256 FROM sequence;
CREATE TABLE t1(a,b,c,d);
CREATE INDEX t1a ON t1(a);
CREATE INDEX t1b ON t1(b);
CREATE INDEX t1cd ON t1(c,d);
INSERT INTO t1 SELECT x, x, x/100, x FROM sequence;
EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;
}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~10 rows)}}
do_test analyze7-1.1 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~10 rows)}}
do_test analyze7-1.2 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~10 rows)}}
# Run an analyze on one of the three indices. Verify that this
# effects the row-count estimate on the one query that uses that
# one index.
#
do_test analyze7-2.0 {
execsql {ANALYZE t1a;}
db cache flush
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}}
do_test analyze7-2.1 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~10 rows)}}
do_test analyze7-2.2 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~10 rows)}}
# Verify that since the query planner now things that t1a is more
# selective than t1b, it prefers to use t1a.
#
do_test analyze7-2.3 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}}
# Run an analysis on another of the three indices. Verify that this
# new analysis works and does not disrupt the previous analysis.
#
do_test analyze7-3.0 {
execsql {ANALYZE t1cd;}
db cache flush;
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}}
do_test analyze7-3.1 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~10 rows)}}
do_test analyze7-3.2 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?) (~102 rows)}}
do_test analyze7-3.3 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}}
do_test analyze7-3.4 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?) (~2 rows)}}
do_test analyze7-3.5 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND c=123}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?) (~1 rows)}}
do_test analyze7-3.6 {
execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND d=123 AND b=123}
} {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=? AND d=?) (~1 rows)}}
finish_test