-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
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
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
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
-7fdb1e2ac2040dc47800a224d33a5c95d55200c480d46fedec1e97fb4f089ef7
\ No newline at end of file
+618ca9fe53d8d2d7b4f368e6ee404d5fceeecac0d689f32ab62af8a6cbb37401
\ No newline at end of file
}
}
#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--;
}
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)
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