From: drh Date: Tue, 14 May 2013 15:31:07 +0000 (+0000) Subject: First attempt to get ORDER BY optimization working in NGQP. X-Git-Tag: version-3.8.0~130^2~77 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=319f677d57a72e49c0618753e1a588d6f5840cf8;p=thirdparty%2Fsqlite.git First attempt to get ORDER BY optimization working in NGQP. FossilOrigin-Name: 9fe20292558bb9422de91e35648cb834cbf3b306 --- diff --git a/manifest b/manifest index 53d49f8c0c..316d75d659 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\sfixes\sto\sthe\sOR-clause\sprocessing\sin\sthe\sNGQP. -D 2013-05-11T00:06:23.252 +C First\sattempt\sto\sget\sORDER\sBY\soptimization\sworking\sin\sNGQP. +D 2013-05-14T15:31:07.121 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in ce81671efd6223d19d4c8c6b88ac2c4134427111 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -195,7 +195,7 @@ F src/shell.c 2109d54f67c815a100abd7dc6a6e25eddb3b97eb F src/sqlite.h.in 5a5a22a9b192d81a9e5dee00274e3a0484c4afb1 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h fab5580c75a16dced398bdd249c0409c9441b466 +F src/sqliteInt.h b9b6a2e97254fb50b6977ec55ad0f4e4ce0510d2 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -264,7 +264,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 049e7011b90717768eed37cdbe912d85f66a395b +F src/where.c 51d935c6593748ed004006ee0f2147a860d56e90 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -1062,7 +1062,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 e17003fcfec0c0b524b1b9ff8e15e7ee83efa571 -R eb646fd2ea7876f6a2dea69031e80ca3 +P d6946f33c7851aa7efb04b93ac2ae1ac50c26eec +R fe984d1689a56a08a31662e67855ab37 U drh -Z cf78dc58c7e86082569e8dd0f46801e5 +Z 13c634b8e2044390ac483fb2d5137194 diff --git a/manifest.uuid b/manifest.uuid index be800b411f..7326bbb499 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d6946f33c7851aa7efb04b93ac2ae1ac50c26eec \ No newline at end of file +9fe20292558bb9422de91e35648cb834cbf3b306 \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 45ae796c44..3ba0a3597b 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2045,7 +2045,7 @@ struct WhereLevel { #define WHERE_FORCE_TABLE 0x0020 /* Do not use an index-only search */ #define WHERE_ONETABLE_ONLY 0x0040 /* Only code the 1st table in pTabList */ #define WHERE_AND_ONLY 0x0080 /* Don't use indices for OR terms */ -#define WHREE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ +#define WHERE_GROUPBY 0x0100 /* pOrderBy is really a GROUP BY */ /* ** The WHERE clause processing routine has two halves. The diff --git a/src/where.c b/src/where.c index d0a3fce772..2eff05ab39 100644 --- a/src/where.c +++ b/src/where.c @@ -84,6 +84,7 @@ struct WhereLoop { */ struct WherePath { Bitmask maskLoop; /* Bitmask of all WhereLoop objects in this path */ + Bitmask revLoop; /* aLoop[]s that should be reversed for ORDER BY */ double nRow; /* Estimated number of rows generated by this path */ double rCost; /* Total cost of this path */ u8 isOrdered; /* True if this path satisfies ORDER BY */ @@ -5078,8 +5079,13 @@ static void whereLoopPrint(WhereLoop *p, SrcList *pTabList){ pItem->zAlias ? pItem->zAlias : pTab->zName); if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){ if( p->u.btree.pIndex ){ - sqlite3DebugPrintf(".%-12s %2d", - p->u.btree.pIndex->zName, p->u.btree.nEq); + const char *zName = p->u.btree.pIndex->zName; + if( strncmp(zName, "sqlite_autoindex_", 17)==0 ){ + int i = sqlite3Strlen30(zName) - 1; + while( zName[i]!='_' ) i--; + zName += i; + } + sqlite3DebugPrintf(".%-12s %2d", zName, p->u.btree.nEq); }else{ sqlite3DebugPrintf("%16s",""); } @@ -5734,25 +5740,139 @@ whereLoopAddAll_end: } /* -** Examine a WherePath to see if it outputs rows in the requested ORDER BY -** (or GROUP BY) without requiring a separate source operation. Return 1 -** if it does and 0 if it does not and -1 if we cannot tell. +** Examine a WherePath (with the addition of the extra WhereLoop of the 4th +** parameters) to see if it outputs rows in the requested ORDER BY +** (or GROUP BY) without requiring a separate source operation. Return: +** +** 0: ORDER BY is not satisfied. Sorting required +** 1: ORDER BY is satisfied. Omit sorting +** -1: Unknown at this time +** */ static int wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ WherePath *pPath, /* The WherePath to check */ int nLoop, /* Number of entries in pPath->aLoop[] */ - WhereLoop *pLoop /* Add this WhereLoop to the end of pPath->aLoop[] */ + WhereLoop *pLast, /* Add this WhereLoop to the end of pPath->aLoop[] */ + Bitmask *pRevMask /* Mask of WhereLoops to run in reverse order */ ){ - if( pLoop->wsFlags & WHERE_VIRTUALTABLE ){ - return nLoop==0 && pLoop->u.vtab.isOrdered; - }else{ - /* TBD: Check to see if pFrom + pWLoop satisfies the ORDER BY. - ** (1) If yes: set isOrderedValid and isOrdered to 1. - ** (2) If no: set isOrderedValid to 1 and isOrdered to 0. - ** (3) unknown: no-op */ - return 0; + u8 revSet; + u8 rev; + u8 isUnique; + u8 requireUnique = 0; + u16 nColumn; + u16 nOrderBy; + int i, j; + int nUsed = 0; + int iCur; + int iColumn; + WhereLoop *pLoop; + ExprList *pOrderBy = pWInfo->pOrderBy; + Expr *pOBExpr; + CollSeq *pColl; + Index *pIndex; + sqlite3 *db = pWInfo->pParse->db; + Bitmask revMask = 0; + + /* + ** We say the WhereLoop is "one-row" if all of the following are true: + ** (a) All index columns match with WHERE_COLUMN_EQ. + ** (b) The index is unique + ** + ** General rules: (not an algorithm!) + ** + ** (1) If the current WhereLoop is one-row, then match over any and all + ** ORDER BY terms for the current WhereLoop and proceed to the next + ** WhereLoop. + ** + ** (2) If the current WhereLoop is not one-row, then all subsequent + ** WhereLoops must be one-row. + ** + ** (3) Optionally match any ORDER BY terms against the first nEq columns + ** of the index. + ** + ** (4) Index columns past nEq must match ORDER BY terms one-for-one. + */ + + assert( pOrderBy!=0 ); + + /* Sortability of virtual tables is determined by the xBestIndex method + ** of the virtual table itself */ + if( pLast->wsFlags & WHERE_VIRTUALTABLE ){ + assert( nLoop==0 ); + return pLast->u.vtab.isOrdered; } + + /* Sorting is always required if any term of the ORDER BY is not a + ** column reference */ + nOrderBy = pOrderBy->nExpr; + for(i=0; ia[nUsed].pExpr); + if( pOBExpr->op!=TK_COLUMN ) return 0; + } + + for(i=0; i<=nLoop && nUsedaLoop[i] : pLast; + assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); + isUnique = 1; + if( pLoop->wsFlags & WHERE_IPK ){ + if( (pLoop->wsFlags & WHERE_COLUMN_EQ)!=0 ) isUnique = 0; + pIndex = 0; + nColumn = 1; + }else if( pLoop->u.btree.pIndex==0 ){ + return 0; + }else{ + pIndex = pLoop->u.btree.pIndex; + nColumn = pIndex->nColumn; + if( pIndex->onError==OE_None ){ + isUnique = 0; + }else if( (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_RANGE + |WHERE_COLUMN_NULL))!=0 ){ + isUnique = 0; + }else if( pLoop->u.btree.nEq < pIndex->nColumn ){ + isUnique = 0; + } + } + if( !isUnique && requireUnique ) return 0; + requireUnique = !isUnique; + iCur = pWInfo->pTabList->a[pLoop->iTab].iCursor; + j = 0; + revSet = rev = 0; + for(j=0; ja[nUsed].pExpr); + assert( pOBExpr->op==TK_COLUMN ); + if( pOBExpr->iTable!=iCur ) break; + if( pIndex==0 ){ + if( pOBExpr->iColumn<0 && j==0 ){ + isUnique = 1; + rev = pOrderBy->a[nUsed].sortOrder; + }else if( isUnique ){ + continue; + }else{ + return 0; + } + } + if( isUnique ) continue; + iColumn = pIndex->aiColumn[j]; + if( iColumn==pIndex->pTable->iPKey ) iColumn = -1; + if( pOBExpr->iColumn!=iColumn ) return 0; + pColl = sqlite3ExprCollSeq(pWInfo->pParse, pOrderBy->a[nUsed].pExpr); + if( !pColl ) pColl = db->pDfltColl; + if( sqlite3StrICmp(pColl->zName, pIndex->azColl[j])!=0 ) return 0; + if( revSet ){ + if( pIndex->aSortOrder[j]!=rev ) return 0; + }else{ + rev = pIndex->aSortOrder[j]; + revSet = 1; + } + } + if( rev ) revMask |= ((Bitmask)1)<pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ Bitmask maskNew; + Bitmask revMask = 0; u8 isOrderedValid = pFrom->isOrderedValid; u8 isOrdered = pFrom->isOrdered; if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; @@ -5840,7 +5961,8 @@ static int wherePathSolver(WhereInfo *pWInfo){ rCost = pWLoop->rSetup + pWLoop->rRun*pFrom->nRow + pFrom->rCost; maskNew = pFrom->maskLoop | pWLoop->maskSelf; if( !isOrderedValid ){ - switch( wherePathSatisfiesOrderBy(pWInfo, pFrom, iLoop, pWLoop) ){ + switch( wherePathSatisfiesOrderBy(pWInfo, pFrom, iLoop, + pWLoop, &revMask) ){ case 1: /* Yes. pFrom+pWLoop does satisfy the ORDER BY clause */ isOrdered = 1; isOrderedValid = 1; @@ -5873,6 +5995,7 @@ static int wherePathSolver(WhereInfo *pWInfo){ } /* pWLoop is a winner. Add it to the set of best so far */ pTo->maskLoop = pFrom->maskLoop | pWLoop->maskSelf; + pTo->revLoop = revMask; pTo->nRow = pFrom->nRow * pWLoop->nOut; pTo->rCost = rCost; pTo->isOrderedValid = isOrderedValid; @@ -6193,7 +6316,12 @@ WhereInfo *sqlite3WhereBegin( && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) if( sqlite3WhereTrace ){ int ii; - sqlite3DebugPrintf("------------ Solution ----------------\n"); + sqlite3DebugPrintf("------------ Solution -------------"); + if( pWInfo->nOBSat ){ + sqlite3DebugPrintf(" ORDER BY omitted\n"); + }else{ + sqlite3DebugPrintf("\n"); + } for(ii=0; iia[ii].pWLoop, pTabList); }