mirror of
https://github.com/sqlite/sqlite.git
synced 2025-12-09 10:21:35 +03:00
Update the omit-table-from-left-join optimization so that it can omit tables
from the middle of the join as well as the end. FossilOrigin-Name: 618ca9fe53d8d2d7b4f368e6ee404d5fceeecac0d689f32ab62af8a6cbb37401
This commit is contained in:
18
manifest
18
manifest
@@ -1,5 +1,5 @@
|
||||
C Fix\sa\sproblem\spreventing\sthe\splanner\sfrom\sidentifying\sscans\sthat\svisit\sat\smost\none\srow\sin\scases\swhere\sthat\sproperty\sis\sguaranteed\sby\sa\sunique,\snot-null,\nnon-IPK\scolumn\sthat\sis\sthe\sleftmost\sin\sits\stable.
|
||||
D 2017-11-20T15:46:10.484
|
||||
C Update\sthe\somit-table-from-left-join\soptimization\sso\sthat\sit\scan\somit\stables\nfrom\sthe\smiddle\sof\sthe\sjoin\sas\swell\sas\sthe\send.
|
||||
D 2017-11-21T19:22:45.416
|
||||
F Makefile.in b142eb20482922153ebc77b261cdfd0a560ed05a81e9f6d9a2b0e8192922a1d2
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc a55372a22454e742ba7c8f6edf05b83213ec01125166ad7dcee0567e2f7fc81b
|
||||
@@ -553,7 +553,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c beeb71e4eab65dbf0d95f2717efc6ca3c0f5b3090ce67f3de63828f39a6ff053
|
||||
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
|
||||
F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f
|
||||
F src/where.c e729f477523e3394892951347f57da1471a94a601133c19efd2573903e60a4a2
|
||||
F src/where.c 9742731e325768332d67df217eb636556c8605f895d518ee61e4d13029f8aed8
|
||||
F src/whereInt.h 82c04c5075308abbac59180c8bad5ecb45b07453981f60a53f3c7dee21e1e971
|
||||
F src/wherecode.c 611fcabd05592ed2febd7d182f9621425b0466c5232d70e0981c842d429356d5
|
||||
F src/whereexpr.c 427ea8e96ec24f2a7814c67b8024ad664a9c7656264c4566c34743cb23186e46
|
||||
@@ -983,7 +983,7 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
|
||||
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
|
||||
F test/join.test 442c462eea85cf065d70a663c626b780a95af6e11585d909bb63b87598afe678
|
||||
F test/join2.test 770a9b6c9f0e91590a102bae707727bce6103b8ad478cea077b2ac126d0698e8
|
||||
F test/join2.test ac70b2b79ac593550d1d6f15e9bb3693dd71826b496e84f15166c5053fa518e6
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
F test/join5.test bc98ea4b4e5003f5b1453701ebb8cd7d1c01a550
|
||||
@@ -1677,8 +1677,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P ee840a7669dd462af072625232ea4238198c9b94e1873f361c45f3b0985456f3 bff5dcfd2b29ee4834258914410a5dee69ec2727dd254053e3ebaf5090937694
|
||||
R e3d55f8947932d938e221f1f7209d770
|
||||
T +closed bff5dcfd2b29ee4834258914410a5dee69ec2727dd254053e3ebaf5090937694
|
||||
P 7fdb1e2ac2040dc47800a224d33a5c95d55200c480d46fedec1e97fb4f089ef7
|
||||
R 77239b01fe37a025cc689347a6c626c1
|
||||
T *branch * left-join-optimization
|
||||
T *sym-left-join-optimization *
|
||||
T -sym-trunk *
|
||||
U dan
|
||||
Z 0d562170c07312a10559bcbda1122c53
|
||||
Z 55e1c0e690d530335519db505e442adf
|
||||
|
||||
@@ -1 +1 @@
|
||||
7fdb1e2ac2040dc47800a224d33a5c95d55200c480d46fedec1e97fb4f089ef7
|
||||
618ca9fe53d8d2d7b4f368e6ee404d5fceeecac0d689f32ab62af8a6cbb37401
|
||||
65
src/where.c
65
src/where.c
@@ -4677,35 +4677,73 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Attempt to omit tables from the join that do not effect the result */
|
||||
|
||||
/* Attempt to omit tables from the join that do not affect the result.
|
||||
** For a table to not affect the result, the following must be true:
|
||||
**
|
||||
** 1) The query must not be an aggregate.
|
||||
** 2) The table must be the RHS of a LEFT JOIN.
|
||||
** 3) Either the query must be DISTINCT, or else the ON or USING clause
|
||||
** must contain a constraint that limits the scan of the table to
|
||||
** at most a single row.
|
||||
** 4) The table must not be referenced by any part of the query apart
|
||||
** from its own USING or ON clause.
|
||||
**
|
||||
** For example, given:
|
||||
**
|
||||
** CREATE TABLE t1(ipk INTEGER PRIMARY KEY, v1);
|
||||
** CREATE TABLE t2(ipk INTEGER PRIMARY KEY, v2);
|
||||
** CREATE TABLE t3(ipk INTEGER PRIMARY KEY, v3);
|
||||
**
|
||||
** then table t2 can be omitted from the following:
|
||||
**
|
||||
** SELECT v1, v3 FROM t1
|
||||
** LEFT JOIN t2 USING (t1.ipk=t2.ipk)
|
||||
** LEFT JOIN t3 USING (t1.ipk=t3.ipk)
|
||||
**
|
||||
** or from:
|
||||
**
|
||||
** SELECT DISTINCT v1, v3 FROM t1
|
||||
** LEFT JOIN t2
|
||||
** LEFT JOIN t3 USING (t1.ipk=t3.ipk)
|
||||
*/
|
||||
if( pWInfo->nLevel>=2
|
||||
&& pResultSet!=0
|
||||
&& pResultSet!=0 /* guarantees condition (1) above */
|
||||
&& OptimizationEnabled(db, SQLITE_OmitNoopJoin)
|
||||
){
|
||||
int i;
|
||||
Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet);
|
||||
if( sWLB.pOrderBy ){
|
||||
tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy);
|
||||
}
|
||||
while( pWInfo->nLevel>=2 ){
|
||||
for(i=pWInfo->nLevel-1; i>=1; i--){
|
||||
WhereTerm *pTerm, *pEnd;
|
||||
pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop;
|
||||
if( (pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 ) break;
|
||||
struct SrcList_item *pItem;
|
||||
pLoop = pWInfo->a[i].pWLoop;
|
||||
pItem = &pWInfo->pTabList->a[pLoop->iTab];
|
||||
if( (pItem->fg.jointype & JT_LEFT)==0 ) continue;
|
||||
if( (wctrlFlags & WHERE_WANT_DISTINCT)==0
|
||||
&& (pLoop->wsFlags & WHERE_ONEROW)==0
|
||||
){
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if( (tabUsed & pLoop->maskSelf)!=0 ) break;
|
||||
if( (tabUsed & pLoop->maskSelf)!=0 ) continue;
|
||||
pEnd = sWLB.pWC->a + sWLB.pWC->nTerm;
|
||||
for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){
|
||||
if( (pTerm->prereqAll & pLoop->maskSelf)!=0
|
||||
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
){
|
||||
break;
|
||||
if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
|
||||
if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|
||||
|| pTerm->pExpr->iRightJoinTable!=pItem->iCursor
|
||||
){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pTerm<pEnd ) break;
|
||||
if( pTerm<pEnd ) continue;
|
||||
WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId));
|
||||
if( i!=pWInfo->nLevel-1 ){
|
||||
int nByte = (pWInfo->nLevel-1-i) * sizeof(WhereLevel);
|
||||
memmove(&pWInfo->a[i], &pWInfo->a[i+1], nByte);
|
||||
}
|
||||
pWInfo->nLevel--;
|
||||
nTabList--;
|
||||
}
|
||||
@@ -4990,7 +5028,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
|
||||
assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 );
|
||||
if( (ws & WHERE_IDX_ONLY)==0 ){
|
||||
sqlite3VdbeAddOp1(v, OP_NullRow, pTabList->a[i].iCursor);
|
||||
assert( pLevel->iTabCur==pTabList->a[pLevel->iFrom].iCursor );
|
||||
sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur);
|
||||
}
|
||||
if( (ws & WHERE_INDEXED)
|
||||
|| ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx)
|
||||
|
||||
@@ -123,4 +123,52 @@ do_eqp_test 3.2 {
|
||||
0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that tables other than the rightmost can be omitted from a
|
||||
# LEFT JOIN query.
|
||||
#
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE c1(k INTEGER PRIMARY KEY, v1);
|
||||
CREATE TABLE c2(k INTEGER PRIMARY KEY, v2);
|
||||
CREATE TABLE c3(k INTEGER PRIMARY KEY, v3);
|
||||
|
||||
INSERT INTO c1 VALUES(1, 2);
|
||||
INSERT INTO c2 VALUES(2, 3);
|
||||
INSERT INTO c3 VALUES(3, 'v3');
|
||||
|
||||
INSERT INTO c1 VALUES(111, 1112);
|
||||
INSERT INTO c2 VALUES(112, 1113);
|
||||
INSERT INTO c3 VALUES(113, 'v1113');
|
||||
}
|
||||
do_execsql_test 4.1.1 {
|
||||
SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2);
|
||||
} {2 v3 1112 {}}
|
||||
do_execsql_test 4.1.2 {
|
||||
SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1);
|
||||
} {2 v3 1112 {}}
|
||||
|
||||
do_execsql_test 4.1.3 {
|
||||
SELECT DISTINCT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1);
|
||||
} {2 v3 1112 {}}
|
||||
|
||||
do_execsql_test 4.1.4 {
|
||||
SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1);
|
||||
} {2 v3 2 v3 1112 {} 1112 {}}
|
||||
|
||||
do_eqp_test 4.2.1 {
|
||||
SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2);
|
||||
} {
|
||||
0 0 0 {SCAN TABLE c1}
|
||||
0 1 1 {SEARCH TABLE c2 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
0 2 2 {SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
do_eqp_test 4.2.2 {
|
||||
SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1);
|
||||
} {
|
||||
0 0 0 {SCAN TABLE c1}
|
||||
0 1 2 {SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?)}
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user