1
0
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:
dan
2017-11-21 19:22:45 +00:00
parent 62a83d262a
commit 41203c6cf1
4 changed files with 111 additions and 22 deletions

View File

@@ -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. 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-20T15:46:10.484 D 2017-11-21T19:22:45.416
F Makefile.in b142eb20482922153ebc77b261cdfd0a560ed05a81e9f6d9a2b0e8192922a1d2 F Makefile.in b142eb20482922153ebc77b261cdfd0a560ed05a81e9f6d9a2b0e8192922a1d2
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc a55372a22454e742ba7c8f6edf05b83213ec01125166ad7dcee0567e2f7fc81b F Makefile.msc a55372a22454e742ba7c8f6edf05b83213ec01125166ad7dcee0567e2f7fc81b
@@ -553,7 +553,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c beeb71e4eab65dbf0d95f2717efc6ca3c0f5b3090ce67f3de63828f39a6ff053 F src/wal.c beeb71e4eab65dbf0d95f2717efc6ca3c0f5b3090ce67f3de63828f39a6ff053
F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f
F src/where.c e729f477523e3394892951347f57da1471a94a601133c19efd2573903e60a4a2 F src/where.c 9742731e325768332d67df217eb636556c8605f895d518ee61e4d13029f8aed8
F src/whereInt.h 82c04c5075308abbac59180c8bad5ecb45b07453981f60a53f3c7dee21e1e971 F src/whereInt.h 82c04c5075308abbac59180c8bad5ecb45b07453981f60a53f3c7dee21e1e971
F src/wherecode.c 611fcabd05592ed2febd7d182f9621425b0466c5232d70e0981c842d429356d5 F src/wherecode.c 611fcabd05592ed2febd7d182f9621425b0466c5232d70e0981c842d429356d5
F src/whereexpr.c 427ea8e96ec24f2a7814c67b8024ad664a9c7656264c4566c34743cb23186e46 F src/whereexpr.c 427ea8e96ec24f2a7814c67b8024ad664a9c7656264c4566c34743cb23186e46
@@ -983,7 +983,7 @@ F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4 F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b F test/ioerr6.test a395a6ab144b26a9e3e21059a1ab6a7149cca65b
F test/join.test 442c462eea85cf065d70a663c626b780a95af6e11585d909bb63b87598afe678 F test/join.test 442c462eea85cf065d70a663c626b780a95af6e11585d909bb63b87598afe678
F test/join2.test 770a9b6c9f0e91590a102bae707727bce6103b8ad478cea077b2ac126d0698e8 F test/join2.test ac70b2b79ac593550d1d6f15e9bb3693dd71826b496e84f15166c5053fa518e6
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
F test/join5.test bc98ea4b4e5003f5b1453701ebb8cd7d1c01a550 F test/join5.test bc98ea4b4e5003f5b1453701ebb8cd7d1c01a550
@@ -1677,8 +1677,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P ee840a7669dd462af072625232ea4238198c9b94e1873f361c45f3b0985456f3 bff5dcfd2b29ee4834258914410a5dee69ec2727dd254053e3ebaf5090937694 P 7fdb1e2ac2040dc47800a224d33a5c95d55200c480d46fedec1e97fb4f089ef7
R e3d55f8947932d938e221f1f7209d770 R 77239b01fe37a025cc689347a6c626c1
T +closed bff5dcfd2b29ee4834258914410a5dee69ec2727dd254053e3ebaf5090937694 T *branch * left-join-optimization
T *sym-left-join-optimization *
T -sym-trunk *
U dan U dan
Z 0d562170c07312a10559bcbda1122c53 Z 55e1c0e690d530335519db505e442adf

View File

@@ -1 +1 @@
7fdb1e2ac2040dc47800a224d33a5c95d55200c480d46fedec1e97fb4f089ef7 618ca9fe53d8d2d7b4f368e6ee404d5fceeecac0d689f32ab62af8a6cbb37401

View File

@@ -4677,35 +4677,73 @@ WhereInfo *sqlite3WhereBegin(
} }
} }
#endif #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 if( pWInfo->nLevel>=2
&& pResultSet!=0 && pResultSet!=0 /* guarantees condition (1) above */
&& OptimizationEnabled(db, SQLITE_OmitNoopJoin) && OptimizationEnabled(db, SQLITE_OmitNoopJoin)
){ ){
int i;
Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet); Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet);
if( sWLB.pOrderBy ){ if( sWLB.pOrderBy ){
tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy); tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy);
} }
while( pWInfo->nLevel>=2 ){ for(i=pWInfo->nLevel-1; i>=1; i--){
WhereTerm *pTerm, *pEnd; WhereTerm *pTerm, *pEnd;
pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop; struct SrcList_item *pItem;
if( (pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 ) break; 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 if( (wctrlFlags & WHERE_WANT_DISTINCT)==0
&& (pLoop->wsFlags & WHERE_ONEROW)==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; pEnd = sWLB.pWC->a + sWLB.pWC->nTerm;
for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){ for(pTerm=sWLB.pWC->a; pTerm<pEnd; pTerm++){
if( (pTerm->prereqAll & pLoop->maskSelf)!=0 if( (pTerm->prereqAll & pLoop->maskSelf)!=0 ){
&& !ExprHasProperty(pTerm->pExpr, EP_FromJoin) if( !ExprHasProperty(pTerm->pExpr, EP_FromJoin)
|| pTerm->pExpr->iRightJoinTable!=pItem->iCursor
){ ){
break; break;
} }
} }
if( pTerm<pEnd ) break; }
if( pTerm<pEnd ) continue;
WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId)); 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--; pWInfo->nLevel--;
nTabList--; nTabList--;
} }
@@ -4990,7 +5028,8 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v); addr = sqlite3VdbeAddOp1(v, OP_IfPos, pLevel->iLeftJoin); VdbeCoverage(v);
assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 ); assert( (ws & WHERE_IDX_ONLY)==0 || (ws & WHERE_INDEXED)!=0 );
if( (ws & WHERE_IDX_ONLY)==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) if( (ws & WHERE_INDEXED)
|| ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx) || ((ws & WHERE_MULTI_OR) && pLevel->u.pCovidx)

View File

@@ -123,4 +123,52 @@ do_eqp_test 3.2 {
0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} 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 finish_test