From: drh Date: Fri, 21 Jun 2013 02:05:06 +0000 (+0000) Subject: Attempt to disable inner loops of a join that do not generate output. X-Git-Tag: version-3.8.0~133^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fd636c7541d0de19ce365fc9e483b88121531c2e;p=thirdparty%2Fsqlite.git Attempt to disable inner loops of a join that do not generate output. This does not work, since the inner loops might run zero times and thus inhibit all output. Needs to be enhanced to work only for LEFT JOINs or when we know that the inner loop will always run at least once. FossilOrigin-Name: ca839723a21bb13d3e0666a672c15c6f3a267c2f --- diff --git a/manifest b/manifest index ede3df5706..2d7ec778f6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Modify\sthe\squery\splanner\sinterface\sso\sthat\sit\salways\spasses\sin\sthe\sresult\sset.\nThis\sis\sthe\sfirst\sstep\stoward\sadding\san\soptimization\sthat\swill\somit\stables\nfrom\sa\sjoin\sthat\sdo\snot\scontribute\sto\sthe\sresult. -D 2013-06-21T00:35:37.456 +C Attempt\sto\sdisable\sinner\sloops\sof\sa\sjoin\sthat\sdo\snot\sgenerate\soutput.\nThis\sdoes\snot\swork,\ssince\sthe\sinner\sloops\smight\srun\szero\stimes\sand\sthus\ninhibit\sall\soutput.\s\sNeeds\sto\sbe\senhanced\sto\swork\sonly\sfor\sLEFT\sJOINs\nor\swhen\swe\sknow\sthat\sthe\sinner\sloop\swill\salways\srun\sat\sleast\sonce. +D 2013-06-21T02:05:06.206 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,14 +289,14 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c c950b131584a40121092d735804472f567beefbc +F src/where.c fc5293b54a70474c2b46e9df26c9e2803b152e68 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 6ff7b43c2b4b905c74dc4a813d201d0fa64c5783 F test/alter.test 57d96ec9b320bd07af77567034488dcb6642c748 -F test/alter2.test 40531b1f89d4fe43f9007b1bfc304e291ed000ae +F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060 F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d F test/alter4.test b2debc14d8cbe4c1d12ccd6a41eef88a8c1f15d5 F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc @@ -1096,10 +1096,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 604c3c5de6fd8f8a569aa9ed981055a5b0123ba1 -R 54a7c9b08c105a408dfe2c4fd7fd4419 -T *branch * omit-join-table-opt -T *sym-omit-join-table-opt * -T -sym-nextgen-query-plan-exp * +P 2c2577e69ccb47f1af674a755e71221e2ca0b322 +R b2263c66dd8a59884ee45351c335261a U drh -Z d2a3072c8b463b513f8068b32a4cb830 +Z 6fd83e64fe937f64082b799e88969f81 diff --git a/manifest.uuid b/manifest.uuid index 169f9d22e6..b8cca3c3d8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2c2577e69ccb47f1af674a755e71221e2ca0b322 \ No newline at end of file +ca839723a21bb13d3e0666a672c15c6f3a267c2f \ No newline at end of file diff --git a/src/where.c b/src/where.c index ab4170fe6f..18b4a3782e 100644 --- a/src/where.c +++ b/src/where.c @@ -392,10 +392,10 @@ struct WhereInfo { u8 okOnePass; /* Ok to use one-pass algorithm for UPDATE/DELETE */ u8 untestedTerms; /* Not all WHERE terms resolved by outer loop */ u8 eDistinct; /* One of the WHERE_DISTINCT_* values below */ + u8 nLevel; /* Number of nested loop */ int iTop; /* The very beginning of the WHERE loop */ int iContinue; /* Jump here to continue with next record */ int iBreak; /* Jump here to break out of the loop */ - int nLevel; /* Number of nested loop */ int savedNQueryLoop; /* pParse->nQueryLoop outside the WHERE loop */ WhereMaskSet sMaskSet; /* Map cursor numbers to bitmasks */ WhereClause sWC; /* Decomposition of the WHERE clause */ @@ -5370,8 +5370,9 @@ static int wherePathSolver(WhereInfo *pWInfo, WhereCost nRowEst){ pLevel->iFrom = pWLoop->iTab; pLevel->iTabCur = pWInfo->pTabList->a[pLevel->iFrom].iCursor; } - if( (pWInfo->wctrlFlags & (WHERE_DISTINCTBY|WHERE_WANT_DISTINCT)) - ==WHERE_WANT_DISTINCT + if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 + && (pWInfo->wctrlFlags & WHERE_DISTINCTBY)==0 + && pWInfo->eDistinct==WHERE_DISTINCT_NOOP && nRowEst ){ Bitmask notUsed; @@ -5571,15 +5572,23 @@ WhereInfo *sqlite3WhereBegin( WhereLoopBuilder sWLB; /* The WhereLoop builder */ WhereMaskSet *pMaskSet; /* The expression mask set */ WhereLevel *pLevel; /* A single level in pWInfo->a[] */ + WhereLoop *pLoop; /* Pointer to a single WhereLoop object */ int ii; /* Loop counter */ sqlite3 *db; /* Database connection */ int rc; /* Return code */ /* Variable initialization */ + db = pParse->db; memset(&sWLB, 0, sizeof(sWLB)); sWLB.pOrderBy = pOrderBy; + /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via + ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ + if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){ + wctrlFlags &= ~WHERE_WANT_DISTINCT; + } + /* The number of tables in the FROM clause is limited by the number of ** bits in a Bitmask */ @@ -5603,7 +5612,6 @@ WhereInfo *sqlite3WhereBegin( ** field (type Bitmask) it must be aligned on an 8-byte boundary on ** some architectures. Hence the ROUND8() below. */ - db = pParse->db; nByteWInfo = ROUND8(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel)); pWInfo = sqlite3DbMallocZero(db, nByteWInfo + sizeof(WhereLoop)); if( db->mallocFailed ){ @@ -5628,12 +5636,6 @@ WhereInfo *sqlite3WhereBegin( sWLB.pNew->cId = '*'; #endif - /* Disable the DISTINCT optimization if SQLITE_DistinctOpt is set via - ** sqlite3_test_ctrl(SQLITE_TESTCTRL_OPTIMIZATIONS,...) */ - if( OptimizationDisabled(db, SQLITE_DistinctOpt) ){ - wctrlFlags &= ~WHERE_WANT_DISTINCT; - } - /* Split the WHERE clause into separate subexpressions where each ** subexpression is separated by an AND operator. */ @@ -5718,7 +5720,6 @@ WhereInfo *sqlite3WhereBegin( if( wctrlFlags & WHERE_WANT_DISTINCT ){ if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){ /* The DISTINCT marking is pointless. Ignore it. */ - wctrlFlags &= ~WHERE_WANT_DISTINCT; pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; }else if( pOrderBy==0 ){ /* Try to ORDER BY the result set to make distinct processing easier */ @@ -5737,11 +5738,11 @@ WhereInfo *sqlite3WhereBegin( #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ WhereLoop *p; - int i = 0; + int i; static char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; - for(p=pWInfo->pLoops; p; p=p->pNextLoop){ - p->cId = zLabel[(i++)%sizeof(zLabel)]; + for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){ + p->cId = zLabel[i%sizeof(zLabel)]; whereLoopPrint(p, pTabList); } } @@ -5782,11 +5783,29 @@ WhereInfo *sqlite3WhereBegin( } } sqlite3DebugPrintf("\n"); - for(ii=0; iinLevel; ii++){ whereLoopPrint(pWInfo->a[ii].pWLoop, pTabList); } } #endif + /* Attempt to omit tables from the join that do not effect the result */ + if( pResultSet!=0 && pWInfo->nLevel>=2 ){ + Bitmask tabUsed = exprListTableUsage(pMaskSet, pResultSet); + if( pOrderBy ) tabUsed |= exprListTableUsage(pMaskSet, pOrderBy); + while( pWInfo->nLevel>=2 ){ + pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop; + if( ((wctrlFlags & WHERE_WANT_DISTINCT)!=0 + || (pLoop->wsFlags & WHERE_ONEROW)!=0) + && (tabUsed & pLoop->maskSelf)==0 + ){ + WHERETRACE(0xffff, ("-> drop loop %c not used\n", pLoop->cId)); + pWInfo->nLevel--; + nTabList--; + }else{ + break; + } + } + } WHERETRACE(0xffff,("*** Optimizer Finished ***\n")); pWInfo->pParse->nQueryLoop += pWInfo->nRowOut; @@ -5955,7 +5974,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ /* Close all of the cursors that were opened by sqlite3WhereBegin. */ - assert( pWInfo->nLevel==1 || pWInfo->nLevel==pTabList->nSrc ); + assert( pWInfo->nLevel<=pTabList->nSrc ); for(i=0, pLevel=pWInfo->a; inLevel; i++, pLevel++){ Index *pIdx = 0; struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom]; diff --git a/test/alter2.test b/test/alter2.test index db8a83bf9f..14be637f97 100644 --- a/test/alter2.test +++ b/test/alter2.test @@ -120,7 +120,6 @@ do_test alter2-1.5 { } } {} do_test alter2-1.6 { -breakpoint execsql { SELECT c FROM abc ORDER BY c; }