Merge the ANALYZE-index enhancement into trunk.
FossilOrigin-Name: 7e237aea22084416d02b89d5223de4e1ca76882d
This commit is contained in:
@@ -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
@@ -1 +1 @@
|
||||
7a6d05dfbc36310683dd51a280e9283cef4f9056
|
||||
7e237aea22084416d02b89d5223de4e1ca76882d
|
||||
+31
-18
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user