From: drh Date: Wed, 16 Jan 2013 00:46:09 +0000 (+0000) Subject: Improvements to query planning for joins: Avoid unnecessary calls to X-Git-Tag: version-3.7.16~72 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3bd5ab863810d4d8397e84742db1d6349e754406;p=thirdparty%2Fsqlite.git Improvements to query planning for joins: Avoid unnecessary calls to "optimal scan" checks in cases where table reordering is not possible. Make sure optimal scan checks are carried out for CROSS JOINs and LEFT JOINs. FossilOrigin-Name: d5ebb7877885839e93eee3b322624d4c4215c1c4 --- diff --git a/manifest b/manifest index b7881441e1..a878fe5539 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\smissing\sword\sin\sa\scomment.\s\sEnhance\sthe\s"wheretrace"\sdebugging\soutput\nto\sshow\sthe\sestimated\scost\sof\seach\stable\soption\swhile\splanning\sthe\sjoin\sorder. -D 2013-01-15T18:49:07.627 +C Improvements\sto\squery\splanning\sfor\sjoins:\s\sAvoid\sunnecessary\scalls\sto\n"optimal\sscan"\schecks\sin\scases\swhere\stable\sreordering\sis\snot\spossible.\nMake\ssure\soptimal\sscan\schecks\sare\scarried\sout\sfor\sCROSS\sJOINs\sand\sLEFT\nJOINs. +D 2013-01-16T00:46:09.175 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 b2a827f2b3fa23a3245a4e6093827e359c1e8054 +F src/where.c d48a57d8afd97c51f1b772ebd72431a43a0e48b3 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -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 04507c176330a06b09dcafa35ec0ca7498f5ace7 -R f5ddb099282326d8029eed3fa99d47e6 +P ac4e119a87497f2e422ff1cb711112ed8594bfa9 +R 604db48c0336d28f8c2561951db4000b U drh -Z f7bf9c2b2fa73cf7872c5f7a932db154 +Z 14d78037173bf002814299854e4b798b diff --git a/manifest.uuid b/manifest.uuid index a55b102705..536565f198 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ac4e119a87497f2e422ff1cb711112ed8594bfa9 \ No newline at end of file +d5ebb7877885839e93eee3b322624d4c4215c1c4 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 84d79c811d..ba39fe9a5d 100644 --- a/src/where.c +++ b/src/where.c @@ -5072,6 +5072,7 @@ WhereInfo *sqlite3WhereBegin( int bestJ = -1; /* The value of j */ Bitmask m; /* Bitmask value for j or bestJ */ int isOptimal; /* Iterator for optimal/non-optimal search */ + int ckOptimal; /* Do the optimal scan check */ int nUnconstrained; /* Number tables without INDEXED BY */ Bitmask notIndexed; /* Mask of tables that cannot use an index */ @@ -5122,17 +5123,41 @@ WhereInfo *sqlite3WhereBegin( */ nUnconstrained = 0; notIndexed = 0; - for(isOptimal=(iFrom=0 && bestJ<0; isOptimal--){ + + /* The optimal scan check only occurs if there are two or more tables + ** available to be reordered */ + if( iFrom==nTabList-1 ){ + ckOptimal = 0; /* Common case of just one table in the FROM clause */ + }else{ + ckOptimal = -1; for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; jjointype & (JT_LEFT|JT_CROSS))!=0; - if( j!=iFrom && doNotReorder ) break; m = getMask(pMaskSet, sWBI.pSrc->iCursor); if( (m & sWBI.notValid)==0 ){ if( j==iFrom ) iFrom++; continue; } + if( j>iFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ) break; + if( ++ckOptimal ) break; + if( (sWBI.pSrc->jointype & JT_LEFT)!=0 ) break; + } + } + assert( ckOptimal==0 || ckOptimal==1 ); + + for(isOptimal=ckOptimal; isOptimal>=0 && bestJ<0; isOptimal--){ + for(j=iFrom, sWBI.pSrc=&pTabList->a[j]; jiFrom && (sWBI.pSrc->jointype & (JT_LEFT|JT_CROSS))!=0 ){ + /* This break and one like it in the ckOptimal computation loop + ** above prevent table reordering across LEFT and CROSS JOINs. + ** The LEFT JOIN case is necessary for correctness. The prohibition + ** against reordering across a CROSS JOIN is an SQLite feature that + ** allows the developer to control table reordering */ + break; + } + m = getMask(pMaskSet, sWBI.pSrc->iCursor); + if( (m & sWBI.notValid)==0 ){ + assert( j>iFrom ); + continue; + } sWBI.notReady = (isOptimal ? m : sWBI.notValid); if( sWBI.pSrc->pIndex==0 ) nUnconstrained++; @@ -5161,7 +5186,7 @@ WhereInfo *sqlite3WhereBegin( } if( isOptimal ){ pWInfo->a[j].rOptCost = sWBI.cost.rCost; - }else if( iFromjointype & JT_LEFT)!=0 ) break; } } assert( bestJ>=0 ); assert( sWBI.notValid & getMask(pMaskSet, pTabList->a[bestJ].iCursor) ); + assert( bestJ==iFrom || (pTabList->a[iFrom].jointype & JT_LEFT)==0 ); + testcase( bestJ>iFrom && (pTabList->a[iFrom].jointype & JT_CROSS)!=0 ); + testcase( bestJ>iFrom && bestJa[bestJ+1].jointype & JT_LEFT)!=0 ); WHERETRACE(("*** Optimizer selects table %d (%s) for loop %d with:\n" " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=0x%08x\n", bestJ, pTabList->a[bestJ].pTab->zName,