1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-22 20:22:44 +03:00

Make more aggressive use of transitivity in optimizing queries. Add a test

case.

FossilOrigin-Name: d96762841a461e192fb2f317d684d000376350dd
This commit is contained in:
drh
2013-01-17 15:05:17 +00:00
parent 58eb1c0af1
commit 738fc79dcf
4 changed files with 144 additions and 20 deletions

View File

@@ -1,5 +1,5 @@
C Improved\scomments\sexplaining\sthe\soperation\sof\sthe\sfindTerm()\sutility\sroutine\nin\swhere.c.\s\sIncrease\sthe\smaximum\snumber\sof\slevels\sof\stransitivity\sfrom\s4\nto\s11.
D 2013-01-17T00:08:42.232
C Make\smore\saggressive\suse\sof\stransitivity\sin\soptimizing\squeries.\s\sAdd\sa\stest\ncase.
D 2013-01-17T15:05:17.153
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -252,7 +252,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83
F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
F src/where.c 24d74ec54a71e01e0672e0838f7dd5757fb6324d
F src/where.c 701c32fecbcf44d749a8fdacb887ffdcec21a3e5
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
@@ -285,7 +285,7 @@ F test/auth.test 304e82f31592820d3bde26ab6b75deaa123e1a6f
F test/auth2.test a2a371aa6df15f8b0c8109b33d3d7f0f73e4c9aa
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf
F test/autoindex1.test 058d0b331ae6840a61bbee910d8cbae27bfd5991
F test/autoindex1.test f88146c4c889ea0afbb620e49d83b5fbf5ee4d06
F test/autovacuum.test 9f22a7733f39c56ef6a5665d10145ac25d8cb574
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
@@ -1033,7 +1033,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
P 13171eb5dc19733276fbfd5515d75b70a9f5f5d7
R 47b8015795abaf8b9e9739389b1b5d3d
P fe152f8b048c9a18f99fa6096ff0e68dd630c318
R f7b812e14ccd12b59aae7b48f0da1945
U drh
Z c72ed7f67d993d6d7e18306e36936017
Z eaf427dd060ebdbe2c55df9e5c68a5b1

View File

@@ -1 +1 @@
fe152f8b048c9a18f99fa6096ff0e68dd630c318
d96762841a461e192fb2f317d684d000376350dd

View File

@@ -663,6 +663,7 @@ static WhereTerm *findTerm(
int j, k; /* Loop counters */
Expr *pX; /* Pointer to an expression */
Parse *pParse; /* Parsing context */
int iOrigCol = iColumn; /* Original value of iColumn */
int nEquiv = 2; /* Number of entires in aEquiv[] */
int iEquiv = 2; /* Number of entries of aEquiv[] processed so far */
int aEquiv[22]; /* iCur,iColumn and up to 10 other equivalents */
@@ -675,16 +676,17 @@ static WhereTerm *findTerm(
for(pTerm=pWC->a, k=pWC->nTerm; k; k--, pTerm++){
if( pTerm->leftCursor==iCur
&& pTerm->u.leftColumn==iColumn
&& (pTerm->eOperator & op & WO_ALL)!=0
){
if( (pTerm->prereqRight & notReady)==0 ){
if( iColumn>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){
if( (pTerm->prereqRight & notReady)==0
&& (pTerm->eOperator & op & WO_ALL)!=0
){
if( iOrigCol>=0 && pIdx && (pTerm->eOperator & WO_ISNULL)==0 ){
CollSeq *pColl;
char idxaff;
pX = pTerm->pExpr;
pParse = pWC->pParse;
idxaff = pIdx->pTable->aCol[iColumn].affinity;
idxaff = pIdx->pTable->aCol[iOrigCol].affinity;
if( !sqlite3IndexAffinityOk(pX, idxaff) ) continue;
/* Figure out the collation sequence required from an index for
@@ -695,7 +697,7 @@ static WhereTerm *findTerm(
pColl = sqlite3BinaryCompareCollSeq(pParse,pX->pLeft,pX->pRight);
if( pColl==0 ) pColl = pParse->db->pDfltColl;
for(j=0; pIdx->aiColumn[j]!=iColumn; j++){
for(j=0; pIdx->aiColumn[j]!=iOrigCol; j++){
if( NEVER(j>=pIdx->nColumn) ) return 0;
}
if( sqlite3StrICmp(pColl->zName, pIdx->azColl[j]) ) continue;
@@ -703,8 +705,7 @@ static WhereTerm *findTerm(
pResult = pTerm;
if( pTerm->prereqRight==0 ) goto findTerm_success;
}
if( (op&WO_EQ)!=0
&& (pTerm->eOperator & WO_EQUIV)!=0
if( (pTerm->eOperator & WO_EQUIV)!=0
&& nEquiv<ArraySize(aEquiv)
){
pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight);
@@ -724,7 +725,6 @@ static WhereTerm *findTerm(
if( iEquiv>=nEquiv ) break;
iCur = aEquiv[iEquiv++];
iColumn = aEquiv[iEquiv++];
op &= WO_EQ;
}
findTerm_success:
return pResult;
@@ -1005,7 +1005,6 @@ static void exprAnalyzeOrTerm(
for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){
if( (pOrTerm->eOperator & WO_SINGLE)==0 ){
WhereAndInfo *pAndInfo;
assert( pOrTerm->eOperator==0 );
assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 );
chngToIN = 0;
pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo));
@@ -1291,13 +1290,14 @@ static void exprAnalyze(
pTerm->leftCursor = -1;
pTerm->iParent = -1;
pTerm->eOperator = 0;
if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){
if( allowedOp(op) ){
Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
if( pLeft->op==TK_COLUMN ){
pTerm->leftCursor = pLeft->iTable;
pTerm->u.leftColumn = pLeft->iColumn;
pTerm->eOperator = operatorMask(op);
pTerm->eOperator = operatorMask(op) & opMask;
}
if( pRight && pRight->op==TK_COLUMN ){
WhereTerm *pNew;
@@ -1332,7 +1332,7 @@ static void exprAnalyze(
testcase( (prereqLeft | extraRight) != prereqLeft );
pNew->prereqRight = prereqLeft | extraRight;
pNew->prereqAll = prereqAll;
pNew->eOperator = operatorMask(pDup->op) + eExtraOp;
pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask;
}
}

View File

@@ -257,5 +257,129 @@ do_execsql_test autoindex1-700 {
0 0 0 {USE TEMP B-TREE FOR ORDER BY}
}
# The following checks a performance issue reported on the sqlite-dev
# mailing list on 2013-01-10
#
do_execsql_test autoindex1-800 {
CREATE TABLE accounts(
_id INTEGER PRIMARY KEY AUTOINCREMENT,
account_name TEXT,
account_type TEXT,
data_set TEXT
);
CREATE TABLE data(
_id INTEGER PRIMARY KEY AUTOINCREMENT,
package_id INTEGER REFERENCES package(_id),
mimetype_id INTEGER REFERENCES mimetype(_id) NOT NULL,
raw_contact_id INTEGER REFERENCES raw_contacts(_id) NOT NULL,
is_read_only INTEGER NOT NULL DEFAULT 0,
is_primary INTEGER NOT NULL DEFAULT 0,
is_super_primary INTEGER NOT NULL DEFAULT 0,
data_version INTEGER NOT NULL DEFAULT 0,
data1 TEXT,
data2 TEXT,
data3 TEXT,
data4 TEXT,
data5 TEXT,
data6 TEXT,
data7 TEXT,
data8 TEXT,
data9 TEXT,
data10 TEXT,
data11 TEXT,
data12 TEXT,
data13 TEXT,
data14 TEXT,
data15 TEXT,
data_sync1 TEXT,
data_sync2 TEXT,
data_sync3 TEXT,
data_sync4 TEXT
);
CREATE TABLE mimetypes(
_id INTEGER PRIMARY KEY AUTOINCREMENT,
mimetype TEXT NOT NULL
);
CREATE TABLE raw_contacts(
_id INTEGER PRIMARY KEY AUTOINCREMENT,
account_id INTEGER REFERENCES accounts(_id),
sourceid TEXT,
raw_contact_is_read_only INTEGER NOT NULL DEFAULT 0,
version INTEGER NOT NULL DEFAULT 1,
dirty INTEGER NOT NULL DEFAULT 0,
deleted INTEGER NOT NULL DEFAULT 0,
contact_id INTEGER REFERENCES contacts(_id),
aggregation_mode INTEGER NOT NULL DEFAULT 0,
aggregation_needed INTEGER NOT NULL DEFAULT 1,
custom_ringtone TEXT,
send_to_voicemail INTEGER NOT NULL DEFAULT 0,
times_contacted INTEGER NOT NULL DEFAULT 0,
last_time_contacted INTEGER,
starred INTEGER NOT NULL DEFAULT 0,
display_name TEXT,
display_name_alt TEXT,
display_name_source INTEGER NOT NULL DEFAULT 0,
phonetic_name TEXT,
phonetic_name_style TEXT,
sort_key TEXT,
sort_key_alt TEXT,
name_verified INTEGER NOT NULL DEFAULT 0,
sync1 TEXT,
sync2 TEXT,
sync3 TEXT,
sync4 TEXT,
sync_uid TEXT,
sync_version INTEGER NOT NULL DEFAULT 1,
has_calendar_event INTEGER NOT NULL DEFAULT 0,
modified_time INTEGER,
is_restricted INTEGER DEFAULT 0,
yp_source TEXT,
method_selected INTEGER DEFAULT 0,
custom_vibration_type INTEGER DEFAULT 0,
custom_ringtone_path TEXT,
message_notification TEXT,
message_notification_path TEXT
);
CREATE INDEX data_mimetype_data1_index ON data (mimetype_id,data1);
CREATE INDEX data_raw_contact_id ON data (raw_contact_id);
CREATE UNIQUE INDEX mime_type ON mimetypes (mimetype);
CREATE INDEX raw_contact_sort_key1_index ON raw_contacts (sort_key);
CREATE INDEX raw_contact_sort_key2_index ON raw_contacts (sort_key_alt);
CREATE INDEX raw_contacts_contact_id_index ON raw_contacts (contact_id);
CREATE INDEX raw_contacts_source_id_account_id_index
ON raw_contacts (sourceid, account_id);
ANALYZE sqlite_master;
INSERT INTO sqlite_stat1
VALUES('raw_contacts','raw_contact_sort_key2_index','1600 4');
INSERT INTO sqlite_stat1
VALUES('raw_contacts','raw_contact_sort_key1_index','1600 4');
INSERT INTO sqlite_stat1
VALUES('raw_contacts','raw_contacts_source_id_account_id_index',
'1600 1600 1600');
INSERT INTO sqlite_stat1
VALUES('raw_contacts','raw_contacts_contact_id_index','1600 1');
INSERT INTO sqlite_stat1 VALUES('mimetypes','mime_type','12 1');
INSERT INTO sqlite_stat1
VALUES('data','data_mimetype_data1_index','9819 2455 3');
INSERT INTO sqlite_stat1 VALUES('data','data_raw_contact_id','9819 7');
INSERT INTO sqlite_stat1 VALUES('accounts',NULL,'1');
DROP TABLE IF EXISTS sqlite_stat3;
ANALYZE sqlite_master;
EXPLAIN QUERY PLAN
SELECT * FROM
data JOIN mimetypes ON (data.mimetype_id=mimetypes._id)
JOIN raw_contacts ON (data.raw_contact_id=raw_contacts._id)
JOIN accounts ON (raw_contacts.account_id=accounts._id)
WHERE mimetype_id=10 AND data14 IS NOT NULL;
} {/SEARCH TABLE data .*SEARCH TABLE raw_contacts/}
do_execsql_test autoindex1-801 {
EXPLAIN QUERY PLAN
SELECT * FROM
data JOIN mimetypes ON (data.mimetype_id=mimetypes._id)
JOIN raw_contacts ON (data.raw_contact_id=raw_contacts._id)
JOIN accounts ON (raw_contacts.account_id=accounts._id)
WHERE mimetypes._id=10 AND data14 IS NOT NULL;
} {/SEARCH TABLE data .*SEARCH TABLE raw_contacts/}
finish_test