From: drh Date: Tue, 5 Jun 2018 20:45:20 +0000 (+0000) Subject: Add the OP_IfNoHope and OP_SeekHit opcodes used to reduce the number of X-Git-Tag: version-3.25.0~207^2~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8c2b6d784b44c601ea600e8cfca9a222ce66b54b;p=thirdparty%2Fsqlite.git Add the OP_IfNoHope and OP_SeekHit opcodes used to reduce the number of unnecessary sqlite3BtreeMovetoUnpacked() calls when checking for an early exit on IN-operator loops. Futher optimizations are likely possible here. FossilOrigin-Name: 6bf251af4347165a470d39457d61ab6d2a06c206db8f30bd8be5dbb388ae8a5b --- diff --git a/manifest b/manifest index ef0a40552a..f16c3e72be 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\san\sOP_NotFound\sopcode\sto\scancel\sfutile\sIN\soperators\searly.\s\sThe\scurrent\nimplementation\sis\ssuboptimal\sbecause\sit\salways\sruns\steh\sOP_NotFound.\s\sThis\nstill\sneeds\sto\sbe\senhanced\sto\sonly\sdo\sthe\sOP_NotFound\sif\sno\sresults\shave\sbeen\nseen\son\sthe\scurrent\sloop. -D 2018-06-05T15:16:25.289 +C Add\sthe\sOP_IfNoHope\sand\sOP_SeekHit\sopcodes\sused\sto\sreduce\sthe\snumber\sof\nunnecessary\ssqlite3BtreeMovetoUnpacked()\scalls\swhen\schecking\sfor\san\searly\nexit\son\sIN-operator\sloops.\s\sFuther\soptimizations\sare\slikely\spossible\shere. +D 2018-06-05T20:45:20.959 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da @@ -565,9 +565,9 @@ F src/upsert.c 47edd408cc73f8d3c00a140550d1ad180b407c146285947969dd09874802bf88 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5 F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157 F src/vacuum.c 37730af7540033135909ecaee3667dddec043293428d8718546d0d64ba4a5025 -F src/vdbe.c fcec6e9ad743f92f0a557f0b61728d001581ee96e18c3e5c7d09702afde79b38 +F src/vdbe.c 1c429876d32a96fdebd8f8b31f735c6236a8fb04395e8f731784767b909d2504 F src/vdbe.h e3f43bcc27ff30b0f25a6104d0cb5657e1c4b5e1b5cd2dd2216d5bcc2156a746 -F src/vdbeInt.h 42d3e65ea0c664f6d9bc9a53de645c0baf8566ff0188409ff3b8d2abc327bc17 +F src/vdbeInt.h d299d7a19853463dac418de0d97f2dd9cb4ddb495a45c93364e2daee109ba0ef F src/vdbeapi.c 765a0bbe01311626417de6cb743f7f25f9f98435c98a9df4bb0714d11014633d F src/vdbeaux.c b00d35805a2b326d1371ab7ce8f3a95c8af35b1431367ffe482fc2c735d69fb1 F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 @@ -579,9 +579,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c aa9cffc7a2bad6b826a86c8562dd4978398720ed41cb8ee7aa9d054eb8b456a0 F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f -F src/where.c a16f982d998e87067ea64d30602e008a24f767e6e502d7cdcddf0c858cdd9392 +F src/where.c 83b6cf94d98ff9a2185071aeed664a57922999a6dd58a03dbb379d472314e4b2 F src/whereInt.h b6ab96d9c1e48d029eaaee8f9b6d05e6a2405af0ad68f684e75f21c46837ae11 -F src/wherecode.c f941a484fd9f7a197099efe384be7a64c5588f27bbf92151705dae92eea7dbfc +F src/wherecode.c 12d88d0195a50b456c5dbeb3c44cb7d7087f591526968e8bde7a38b5534cd0ee F src/whereexpr.c e90b2e76dcabc81edff56633bf281bc01d93b71e0c81482dc06925ce39f5844a F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -1730,7 +1730,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 047295c588e9fdf2ffa4e69e166f177fd193309531dc6a9ac755fb7a763adb72 -R 5115dc97bd8a224dc2a595e1eda36012 +P 87a9fc504f9a78caf7a7949cc7ada0a19d61bfab51bb49a00a1607194c116212 +R 06e6068952816b400d67d388d7704be4 U drh -Z 3e5cea1662f3befc7bce81830cbd86be +Z 5b6bba2950cd0e23a4c3733c8955eb63 diff --git a/manifest.uuid b/manifest.uuid index 20f95cb085..9568d071fe 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -87a9fc504f9a78caf7a7949cc7ada0a19d61bfab51bb49a00a1607194c116212 \ No newline at end of file +6bf251af4347165a470d39457d61ab6d2a06c206db8f30bd8be5dbb388ae8a5b \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 27bf56eb46..4a325b207b 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -4034,6 +4034,25 @@ seek_not_found: break; } +/* Opcode: SeekHit P1 P2 * * * +** Synopsis: seekHit=P2 +** +** Set the seekHit flag on cursor P1 to the value in P2. +** The seekHit flag is used by the IfNoHope opcode. +** +** P1 must be a valid b-tree cursor. P2 must be a boolean value, +** either 0 or 1. +*/ +case OP_SeekHit: { + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + assert( pOp->p2==0 || pOp->p2==1 ); + pC->seekHit = pOp->p2 & 1; + break; +} + /* Opcode: Found P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] ** @@ -4068,7 +4087,34 @@ seek_not_found: ** advanced in either direction. In other words, the Next and Prev ** opcodes do not work after this operation. ** -** See also: Found, NotExists, NoConflict +** See also: Found, NotExists, NoConflict, IfNoHope +*/ +/* Opcode: IfNoHope P1 P2 P3 P4 * +** Synopsis: key=r[P3@P4] +** +** Register P3 is the first of P4 registers that form an unpacked +** record. +** +** Cursor P1 is on an index btree. If the seekHit flag is set on P1, then +** this opcode is a no-op. But if the seekHit flag of P1 is clear, then +** check to see if there is any entry in P1 that matches the +** prefix identified by P3 and P4. If no entry matches the prefix, +** jump to P2. Otherwise fall through. +** +** This opcode behaves like OP_NotFound if the seekHit +** flag is clear and it behaves like OP_Noop if the seekHit flag is set. +** +** This opcode is used in IN clause processing for a multi-column key. +** If an IN clause is attached to an element of the key other than the +** left-most element, and if there are no matches on the most recent +** seek over the whole key, then it might be that one of the key element +** to the left is prohibiting a match, and hence there is "no hope" of +** any match regardless of how many IN clause elements are checked. +** In such a case, we abandon the IN clause search early, using this +** opcode. The opcode name comes from the fact that the +** jump is taken if there is "no hope" of achieving a match. +** +** See also: NotFound, SeekHit */ /* Opcode: NoConflict P1 P2 P3 P4 * ** Synopsis: key=r[P3@P4] @@ -4093,6 +4139,14 @@ seek_not_found: ** ** See also: NotFound, Found, NotExists */ +case OP_IfNoHope: { /* jump, in3 */ + VdbeCursor *pC; + assert( pOp->p1>=0 && pOp->p1nCursor ); + pC = p->apCsr[pOp->p1]; + assert( pC!=0 ); + if( pC->seekHit ) break; + /* Fall through into OP_NotFound */ +} case OP_NoConflict: /* jump, in3 */ case OP_NotFound: /* jump, in3 */ case OP_Found: { /* jump, in3 */ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 0f10e3759d..dd8e29108a 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -85,6 +85,7 @@ struct VdbeCursor { Bool isEphemeral:1; /* True for an ephemeral table */ Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */ Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */ + Bool seekHit:1; /* See the OP_SeekHit and OP_IfNoHope opcodes */ Btree *pBtx; /* Separate file holding temporary table */ i64 seqCount; /* Sequence counter */ int *aAltMap; /* Mapping from table to index column numbers */ diff --git a/src/where.c b/src/where.c index d31e0bb09d..bfb848f426 100644 --- a/src/where.c +++ b/src/where.c @@ -5084,7 +5084,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ sqlite3VdbeJumpHere(v, pIn->addrInTop+1); if( pIn->eEndLoopOp!=OP_Noop ){ if( pIn->nPrefix ){ - sqlite3VdbeAddOp4Int(v, OP_NotFound, pLevel->iIdxCur, + sqlite3VdbeAddOp4Int(v, OP_IfNoHope, pLevel->iIdxCur, sqlite3VdbeCurrentAddr(v)+2, pIn->iBase, pIn->nPrefix); VdbeCoverage(v); diff --git a/src/wherecode.c b/src/wherecode.c index 1c653c9f59..a20a9808e1 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -1664,6 +1664,9 @@ Bitmask sqlite3WhereCodeOneLoopStart( ** above has already left the cursor sitting on the correct row, ** so no further seeking is needed */ }else{ + if( pLoop->wsFlags & WHERE_IN_ABLE ){ + sqlite3VdbeAddOp1(v, OP_SeekHit, iIdxCur); + } op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; assert( op!=0 ); sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); @@ -1727,6 +1730,10 @@ Bitmask sqlite3WhereCodeOneLoopStart( testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); } + if( pLoop->wsFlags & WHERE_IN_ABLE ){ + sqlite3VdbeAddOp2(v, OP_SeekHit, iIdxCur, 1); + } + /* Seek the table cursor, if required */ if( omitTable ){ /* pIdx is a covering index. No need to access the main table. */