]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
In a query with both ORDER BY and LIMIT, if the inner loop satisfies the
authordrh <drh@noemail.net>
Thu, 19 May 2016 22:13:37 +0000 (22:13 +0000)
committerdrh <drh@noemail.net>
Thu, 19 May 2016 22:13:37 +0000 (22:13 +0000)
ORDER BY then try to cut short each invocation of the inner loop once the
LIMIT has been satisfied.  This check-in is a partial implementation only.

FossilOrigin-Name: 852d1eda6ecca1171f6ed800b06f5b4854672002

manifest
manifest.uuid
src/select.c
src/sqliteInt.h
src/where.c
src/whereInt.h

index 89053f9deb4dfffa9dd362c355323285a4a55d8d..d01cdd7db82dc18ec1206cfbc81bd724db65f986 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fixup\scomments\son\swctrlFlags\svalue\sdefinitions.
-D 2016-05-19T19:31:30.127
+C In\sa\squery\swith\sboth\sORDER\sBY\sand\sLIMIT,\sif\sthe\sinner\sloop\ssatisfies\sthe\s\nORDER\sBY\sthen\stry\sto\scut\sshort\seach\sinvocation\sof\sthe\sinner\sloop\sonce\sthe\nLIMIT\shas\sbeen\ssatisfied.\s\sThis\scheck-in\sis\sa\spartial\simplementation\sonly.
+D 2016-05-19T22:13:37.318
 F Makefile.in f59e0763ff448719fc1bd25513882b0567286317
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc 306d73e854b1a92ea06e5d1e637faa5c44de53c7
@@ -378,12 +378,12 @@ F src/printf.c a5f0ca08ddede803c241266abb46356ec748ded1
 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
 F src/resolve.c cca3aa77b95706df5d635a2141a4d1de60ae6598
 F src/rowset.c 49eb91c588a2bab36647368e031dc5b66928149d
-F src/select.c fd4a7ce2937497181063cfedb92058ac89491a5d
+F src/select.c 131eeddfcaf3777c4acd4727bf742b98af8183b5
 F src/shell.c 14ff7f660530a52b117d110ba3390b7b2eb719b6
 F src/sqlite.h.in 9984129d86243424b765fcb3f147c697bd20bb54
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 98f72cbfe00169c39089115427d06ea05fe4b4a2
-F src/sqliteInt.h 19de316bfce65ff074b379a67b493a446f3cf8ee
+F src/sqliteInt.h 863cf0d421611ccfa30541ee5ffe761c896ffa5b
 F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
 F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba
 F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
@@ -458,8 +458,8 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
 F src/wal.c 4db22ed7e77bcf672b1a685d6ddeffba8d5be302
 F src/wal.h 2f7c831cf3b071fa548bf2d5cac640846a7ff19c
 F src/walker.c 0f142b5bd3ed2041fc52d773880748b212e63354
-F src/where.c 72fd2e1258625c1aee8e33a529914aea2d487422
-F src/whereInt.h 3b1fc240e322613ba4e9dc857ca9c7c3390acc74
+F src/where.c a7454e62ca13f1ff54892339022f8cb0a8bb3728
+F src/whereInt.h 6e18240be400bef8e4dbafea605251707c5dbf49
 F src/wherecode.c e3f18fcda2d7f8218a09dc33cf495dca0efa6e3e
 F src/whereexpr.c eacc0e60d029a082b4fc0cc42ea98544add1319e
 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
@@ -1489,7 +1489,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P d01305841da94b2d47e32744802f69525bf590df
-R be830660ecf90ba00189952af638cb97
+P 58b516e8c0b00a41bc0364eab267bc2ecb9efeff
+R 766495aa6109f75a3c3b0e829e8d3b47
+T *branch * orderby-limit
+T *sym-orderby-limit *
+T -sym-trunk *
 U drh
-Z 54bddff0ee366139e2fb13081e6cf75a
+Z 1f191cc43f073ab10b6b672b5a12f950
index 177ef2d35a769f032dd366f1bd1208eddfcc287c..ec9b410bfaaab5d08df978a9ab51d3248e17a0a0 100644 (file)
@@ -1 +1 @@
-58b516e8c0b00a41bc0364eab267bc2ecb9efeff
\ No newline at end of file
+852d1eda6ecca1171f6ed800b06f5b4854672002
\ No newline at end of file
index eb37536b6f89ec3d8b44889563d1b0b2f0c67f28..080ccf348017f3dcd43dea3d3d3453e4cbf1eb08 100644 (file)
@@ -56,6 +56,7 @@ struct SortCtx {
   int addrSortIndex;    /* Address of the OP_SorterOpen or OP_OpenEphemeral */
   int labelDone;        /* Jump here when done, ex: LIMIT reached */
   u8 sortFlags;         /* Zero or more SORTFLAG_* bits */
+  u8 bOrderedInnerLoop; /* ORDER BY correctly sorts the inner loop */
 };
 #define SORTFLAG_UseSorter  0x01   /* Use SorterOpen instead of OpenEphemeral */
 
@@ -589,9 +590,29 @@ static void pushOntoSorter(
   sqlite3VdbeAddOp2(v, op, pSort->iECursor, regRecord);
   if( iLimit ){
     int addr;
+    int r1 = 0;
+    /* Fill the sorter until it contains LIMIT+OFFSET entries.  (The iLimit
+    ** register is initialized with value of LIMIT+OFFSET.)  After the sorter
+    ** fills up, delete the least entry in the sorter after each insert.
+    ** Thus we never hold more than the LIMIT+OFFSET rows in memory at once */
     addr = sqlite3VdbeAddOp3(v, OP_IfNotZero, iLimit, 0, 1); VdbeCoverage(v);
     sqlite3VdbeAddOp1(v, OP_Last, pSort->iECursor);
+    if( pSort->bOrderedInnerLoop ){
+      r1 = ++pParse->nMem;
+      sqlite3VdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr, r1);
+      VdbeComment((v, "seq"));
+    }
     sqlite3VdbeAddOp1(v, OP_Delete, pSort->iECursor);
+    if( pSort->bOrderedInnerLoop ){
+      /* If the inner loop is driven by an index such that values from
+      ** the same iteration of the inner loop are in sorted order, then
+      ** immediately jump to the next iteration of an inner loop if the
+      ** entry from the current iteration does not fit into the top
+      ** LIMIT+OFFSET entries of the sorter. */
+      int iBrk = sqlite3VdbeCurrentAddr(v) + 2;
+      sqlite3VdbeAddOp3(v, OP_Eq, regBase+nExpr, iBrk, r1);
+      VdbeCoverage(v);
+    }
     sqlite3VdbeJumpHere(v, addr);
   }
 }
@@ -5176,6 +5197,7 @@ int sqlite3Select(
     }
     if( sSort.pOrderBy ){
       sSort.nOBSat = sqlite3WhereIsOrdered(pWInfo);
+      sSort.bOrderedInnerLoop = sqlite3WhereOrderedInnerLoop(pWInfo);
       if( sSort.nOBSat==sSort.pOrderBy->nExpr ){
         sSort.pOrderBy = 0;
       }
index c7950366667412c449197fe00903997cd0ddcb2f..7adfd3779b96ee81a6a47180b4b111f1817159ff 100644 (file)
@@ -3637,6 +3637,7 @@ void sqlite3WhereEnd(WhereInfo*);
 LogEst sqlite3WhereOutputRowCount(WhereInfo*);
 int sqlite3WhereIsDistinct(WhereInfo*);
 int sqlite3WhereIsOrdered(WhereInfo*);
+int sqlite3WhereOrderedInnerLoop(WhereInfo*);
 int sqlite3WhereIsSorted(WhereInfo*);
 int sqlite3WhereContinueLabel(WhereInfo*);
 int sqlite3WhereBreakLabel(WhereInfo*);
index f6f6f68eabca788c65dacec534c7649eca717e12..521d2e19ec24f76a0960b3e623c011edf69af63f 100644 (file)
@@ -51,6 +51,18 @@ int sqlite3WhereIsOrdered(WhereInfo *pWInfo){
   return pWInfo->nOBSat;
 }
 
+/*
+** Return TRUE if the innermost loop of the WHERE clause implementation
+** returns rows in ORDER BY order for complete run of the inner loop.
+**
+** Across multiple iterations of outer loops, the output rows need not be
+** sorted.  As long as rows are sorted for just the innermost loop, this
+** routine can return TRUE.
+*/
+int sqlite3WhereOrderedInnerLoop(WhereInfo *pWInfo){
+  return pWInfo->bOrderedInnerLoop;
+}
+
 /*
 ** Return the VDBE address or label to jump to in order to continue
 ** immediately with the next row of a WHERE clause.
@@ -3898,8 +3910,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
       }
     }else{
       pWInfo->nOBSat = pFrom->isOrdered;
-      if( pWInfo->nOBSat<0 ) pWInfo->nOBSat = 0;
       pWInfo->revMask = pFrom->revLoop;
+      if( pWInfo->nOBSat<=0 ){
+        pWInfo->nOBSat = 0;
+      }
     }
     if( (pWInfo->wctrlFlags & WHERE_SORTBYGROUP)
         && pWInfo->nOBSat==pWInfo->pOrderBy->nExpr && nLoop>0
index d33d995af178bcba5143615345a55a0f5517f20a..ed6b198e4be121916c123f8d34828ab5b01c1478 100644 (file)
@@ -418,8 +418,9 @@ struct WhereInfo {
   u8 sorted;                /* True if really sorted (not just grouped) */
   u8 eOnePass;              /* ONEPASS_OFF, or _SINGLE, or _MULTI */
   u8 untestedTerms;         /* Not all WHERE terms resolved by outer loop */
-  u8 eDistinct;             /* One of the WHERE_DISTINCT_* values below */
+  u8 eDistinct;             /* One of the WHERE_DISTINCT_* values */
   u8 nLevel;                /* Number of nested loop */
+  u8 bOrderedInnerLoop;     /* True if only the inner-most loop is ordered */
   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 */