From: dan Date: Sat, 18 Feb 2017 20:05:05 +0000 (+0000) Subject: Add an optimization to OP_Column to speed up sequential OP_Column X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2352d1333c8994b901e536f25b68b28888bfd8ac;p=thirdparty%2Fsqlite.git Add an optimization to OP_Column to speed up sequential OP_Column instructions that read earlier fields from the same cursor. Attempt to reorder OP_Column opcodes so as to take advantage of this. FossilOrigin-Name: c1adf95958d5210bf9f89fc86d0f6fc6ce32c480 --- diff --git a/manifest b/manifest index 44763338e4..0a428956a4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sSQLITE_BUG_COMPATIBLE_20160819\scompile-time\soption\sto\somit\sthe\serror\nmessage\swhen\san\sunrecognized\sargument\sis\sprovided\sto\sthe\sVACUUM\scommand. -D 2017-02-18T13:47:11.181 +C Add\san\soptimization\sto\sOP_Column\sto\sspeed\sup\ssequential\sOP_Column\ninstructions\sthat\sread\searlier\sfields\sfrom\sthe\ssame\scursor.\sAttempt\sto\sreorder\nOP_Column\sopcodes\sso\sas\sto\stake\sadvantage\sof\sthis. +D 2017-02-18T20:05:05.184 F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc a89ea37ab5928026001569f056973b9059492fe2 @@ -347,7 +347,7 @@ F src/ctime.c a9984df73898c042a5cfc8f9d8e7723d02bc35c9 F src/date.c dc3f1391d9297f8c748132813aaffcb117090d6e F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d F src/delete.c 0d9d5549d42e79ce4d82ff1db1e6c81e36d2f67c -F src/expr.c 8a29e9b72d4b642189999c41782cd6c5bc43512f +F src/expr.c 980e4627f5d5efe8366ca5123e9d393e495a404c F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 2e9aabe1aee76273aff8a84ee92c464e095400ae F src/func.c c67273e1ec08abbdcc14c189892a3ff6eeece86b @@ -394,12 +394,12 @@ F src/printf.c 67427bbee66d891fc6f6f5aada857e9cdb368c1c F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c f9bc0de45a30a450da47b3766de00be89bf9be79 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac -F src/select.c d12f3539f80db38b09015561b569e0eb1c4b6c5f +F src/select.c e32cc5c546d77c217d1b61b17eb953471c8bbd19 F src/shell.c bf976d5301be9d8a4c52852c97909cc9a41ee20d F src/sqlite.h.in 751ff125eb159c8f92c182b8df980a5e4f50e966 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae -F src/sqliteInt.h 46fe8e5aee3825d77fa771216ef263dc947030e7 +F src/sqliteInt.h e30c066962672158359575ddd550db8200107275 F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247 F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -457,15 +457,15 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c 25ccc63ae2c4163933221f3181c9982b47cd08d2 F src/treeview.c 4e44ade3bfe59d82005039f72e09333ce2b4162c F src/trigger.c c9f0810043b265724fdb1bdd466894f984dfc182 -F src/update.c 456d4a4656f8a03c2abc88a51b19172197400e58 +F src/update.c bcfda1d123d19e86479a619e37a2f3b5aaa978e5 F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c F src/util.c ca8440ede81e155d15cff7c101654f60b55a9ae6 F src/vacuum.c 1fe4555cd8c9b263afb85b5b4ee3a4a4181ad569 -F src/vdbe.c 16f378640570c24442fd7191b136b5d6380f5c7b -F src/vdbe.h 59998ffd71d7caa8886bc78dafaf8caeccd4c13c -F src/vdbeInt.h 4e4b15b2e1330e1636e4e01974eab2b0b985092f +F src/vdbe.c 337429082b858125a6dee0803a2140039a94ab07 +F src/vdbe.h 0a52f346f6c89ab144adc11d1c04e94f74425eaa +F src/vdbeInt.h 6186ba2bd4d4299ada9c17a61a23761c4cb5757b F src/vdbeapi.c 3e4a8893feeb78620f4aac4ac5b85d92255b97e1 -F src/vdbeaux.c 4122458d33318ab039c4b5da1ca4e7c9221c38e4 +F src/vdbeaux.c fb1d5bfb60ba6b75a964d91fe5d054cb3dd31839 F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9 F src/vdbemem.c 3b5a9a5b375458d3e12a50ae1aaa41eeec2175fd F src/vdbesort.c eda25cb2d1727efca6f7862fea32b8aa33c0face @@ -477,7 +477,7 @@ F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71 F src/walker.c 91a6df7435827e41cff6bb7df50ea00934ee78b0 F src/where.c 01baf58b72f3ddb7793cdee2871f751e3e09b35e F src/whereInt.h c0b092180f04608d80c258174b0a14a1f9c8d02f -F src/wherecode.c 677e95413c472c0b413023b6b69a47f40fce1b04 +F src/wherecode.c 373faba5f8df4d22cd3db9f239ec71a1d0c99e8b F src/whereexpr.c 130cdd1a43af71b19755270fb1224874cf55158c F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -1556,7 +1556,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 8cc9d74c176a78aeebfbb39198c21b5dd547ff52 -R 57839b570efd132c834489fe34d93e5e -U drh -Z 38cfd439ab0cfeae01cbf1d291727475 +P 491814272dce7e937b4734fcbc2ad69e12377b56 +R edee9ca5068aff62e1a1b155721f75af +T *branch * sort-column-opcodes +T *sym-sort-column-opcodes * +T -sym-trunk * +U dan +Z b7f122691d1e00c6c9a153ed5456e504 diff --git a/manifest.uuid b/manifest.uuid index 557d9a7e8b..39a2c60c5a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -491814272dce7e937b4734fcbc2ad69e12377b56 \ No newline at end of file +c1adf95958d5210bf9f89fc86d0f6fc6ce32c480 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 2bf76eb0d7..2c9f3f4968 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4152,6 +4152,104 @@ void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ exprToRegister(pExpr, iMem); } +/* +** Return the value of (*p1) - (*p2), as defined by the sort order described +** in the comment above reorderColumnFetch(). +*/ +static int compareOpCode(VdbeOp *p1, VdbeOp *p2){ + int res; + + assert( p1->opcode==OP_Column || p1->opcode==OP_VColumn + || p1->opcode==OP_Copy || p1->opcode==OP_SCopy + || p1->opcode==OP_Rowid || p1->opcode==OP_RealAffinity + ); + assert( p2->opcode==OP_Column || p2->opcode==OP_VColumn + || p2->opcode==OP_Copy || p2->opcode==OP_SCopy + || p2->opcode==OP_Rowid || p2->opcode==OP_RealAffinity + ); + + assert( OP_VColumn>OP_Column && OP_Rowid>OP_Column ); + assert( OP_Column>OP_RealAffinity ); + assert( OP_RealAffinity>OP_Copy && OP_RealAffinity>OP_SCopy ); + + res = (int)(p2->opcode) - (int)(p1->opcode); + if( res==0 ){ + res = p1->p1 - p2->p1; + if( res==0 ){ + res = p2->p2 - p1->p2; + } + } + return res; +} + +/* +** The VM instructions from iFirst to the current address were generated +** in order to populate an array of registers with the results of a series +** of TK_COLUMN expressions. This guarantees that the specified range +** contains opcodes of the following types only: +** +** Rowid +** Column +** VColumn +** RealAffinity +** Copy +** SCopy +** +** This function sorts the opcodes so all of the OP_Column appear in a +** contiguous block, sorted by (p1, p2 DESC). The VDBE layer processes +** OP_Column instructions in this order more efficiently. +** +** In practice, the array is sorted so that all instructions of each type +** of opcode are arranged into a contiguous group. Given the following, +** this is a safe re-ordering: +** +** * All Rowid, VColumn and Column instructions appear before all +** RealAffinity instructions (that might operate on the result of +** a VColumn or Column), and +** +** * All RealAffinity instructions occur before all Copy and SCopy +** instructions (which might read a column-cache entry populated +** by a prior Column+RealAffinity). +*/ +static void reorderColumnFetch(sqlite3 *db, Vdbe *v, int iFirst){ + int iEnd = sqlite3VdbeCurrentAddr(v); + int nOp = iEnd-iFirst; + if( nOp>1 ){ + VdbeOp *aSpace = (VdbeOp*)sqlite3StackAllocRaw(db, sizeof(VdbeOp) * nOp); + if( aSpace ){ + int sz; + VdbeOp *aOp = sqlite3VdbeGetOp(v, iFirst); + VdbeOp *a1 = aOp; + VdbeOp *a2 = aSpace; + for(sz=1; sz=e1 || (i2pVdbe; assert( pList!=0 ); @@ -4186,6 +4285,14 @@ int sqlite3ExprCodeExprList( if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR; for(pItem=pList->a, i=0; ipExpr; + if( iFirst>0 ){ + if( pExpr->op!=TK_COLUMN ){ + reorderColumnFetch(pParse->db, v, iFirst); + iFirst = -1; + } + }else{ + if( pExpr->op==TK_COLUMN ) iFirst = sqlite3VdbeCurrentAddr(v); + } if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){ if( flags & SQLITE_ECEL_OMITREF ){ i--; @@ -4211,6 +4318,7 @@ int sqlite3ExprCodeExprList( } } } + if( iFirst>0 ) reorderColumnFetch(pParse->db, v, iFirst); return n; } diff --git a/src/select.c b/src/select.c index d817ebd074..d18f002bca 100644 --- a/src/select.c +++ b/src/select.c @@ -1274,15 +1274,22 @@ static void generateSortTail( iSortTab = iTab; bSeq = 1; } - for(i=0, iCol=nKey+bSeq; i=0; i--){ + if( aOutEx[i].u.x.iOrderByCol==0 ){ + sqlite3VdbeAddOp3(v, OP_Column, iSortTab, --iCol, regRow+i); + VdbeComment((v, "%s", aOutEx[i].zName?aOutEx[i].zName:aOutEx[i].zSpan)); + } + } + for(i=nSortData-1; i>=0; i--){ if( aOutEx[i].u.x.iOrderByCol ){ - iRead = aOutEx[i].u.x.iOrderByCol-1; - }else{ - iRead = iCol++; + int iRead = aOutEx[i].u.x.iOrderByCol-1; + sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i); + VdbeComment((v, "%s", aOutEx[i].zName?aOutEx[i].zName:aOutEx[i].zSpan)); } - sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i); - VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan)); } switch( eDest ){ case SRT_Table: diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 9a53d33626..a5965ade1a 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3081,6 +3081,8 @@ struct AuthContext { #define OPFLAG_SAVEPOSITION 0x02 /* OP_Delete/Insert: save cursor pos */ #define OPFLAG_AUXDELETE 0x04 /* OP_Delete: index in a DELETE op */ +#define OPFLAG_CONTINUE 0x01 + /* * Each trigger present in the database schema is stored as an instance of * struct Trigger. diff --git a/src/update.c b/src/update.c index 8fca7eb988..d2bd785cac 100644 --- a/src/update.c +++ b/src/update.c @@ -547,7 +547,11 @@ void sqlite3Update( newmask = sqlite3TriggerColmask( pParse, pTrigger, pChanges, 1, TRIGGER_BEFORE, pTab, onError ); +#if 1 + for(i=pTab->nCol-1; i>=0; i--){ +#else for(i=0; inCol; i++){ +#endif if( i==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regNew+i); }else{ diff --git a/src/vdbe.c b/src/vdbe.c index 7f286b2c6d..2c9ac2f97d 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -553,7 +553,6 @@ static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){ } } - /* ** Execute as much of a VDBE program as we can. ** This is the core of sqlite3_step(). @@ -2627,27 +2626,42 @@ case OP_Column: { if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ - zData = pC->aRow + aOffset[p2]; - if( t<12 ){ - sqlite3VdbeSerialGet(zData, t, pDest); - }else{ - /* If the column value is a string, we need a persistent value, not - ** a MEM_Ephem value. This branch is a fast short-cut that is equivalent - ** to calling sqlite3VdbeSerialGet() and sqlite3VdbeDeephemeralize(). - */ - static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; - pDest->n = len = (t-12)/2; - pDest->enc = encoding; - if( pDest->szMalloc < len+2 ){ - pDest->flags = MEM_Null; - if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; + while( 1 ){ + zData = pC->aRow + aOffset[p2]; + if( t<12 ){ + sqlite3VdbeSerialGet(zData, t, pDest); }else{ - pDest->z = pDest->zMalloc; + /* If the column value is a string, we need a persistent value, not + ** a MEM_Ephem value. This branch is a fast short-cut that is + ** equivalent to calling sqlite3VdbeSerialGet() and + ** sqlite3VdbeDeephemeralize(). + */ + static const u16 aFlag[] = { MEM_Blob, MEM_Str|MEM_Term }; + pDest->n = len = (t-12)/2; + pDest->enc = encoding; + if( pDest->szMalloc < len+2 ){ + pDest->flags = MEM_Null; + if( sqlite3VdbeMemGrow(pDest, len+2, 0) ) goto no_mem; + }else{ + pDest->z = pDest->zMalloc; + } + memcpy(pDest->z, zData, len); + pDest->z[len] = 0; + pDest->z[len+1] = 0; + pDest->flags = aFlag[t&1]; + } + + if( (pOp->p5 & OPFLAG_CONTINUE)==0 ) break; + UPDATE_MAX_BLOBSIZE(pDest); + REGISTER_TRACE(pOp->p3, pDest); + pOp++; + p2 = pOp->p2; + t = pC->aType[p2]; + pDest = &aMem[pOp->p3]; + memAboutToChange(p, pDest); + if( VdbeMemDynamic(pDest) ){ + sqlite3VdbeMemSetNull(pDest); } - memcpy(pDest->z, zData, len); - pDest->z[len] = 0; - pDest->z[len+1] = 0; - pDest->flags = aFlag[t&1]; } }else{ pDest->enc = encoding; diff --git a/src/vdbe.h b/src/vdbe.h index a35f3be344..267355f5ed 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -226,6 +226,7 @@ void sqlite3VdbeSwap(Vdbe*,Vdbe*); VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*); sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8); void sqlite3VdbeSetVarmask(Vdbe*, int); +void sqlite3VdbeUsesAltMap(Vdbe*); #ifndef SQLITE_OMIT_TRACE char *sqlite3VdbeExpandSql(Vdbe*, const char*); #endif diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 989cdfd346..dc380ee673 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -390,6 +390,7 @@ struct Vdbe { bft readOnly:1; /* True for statements that do not write */ bft bIsReader:1; /* True for statements that read */ bft isPrepareV2:1; /* True if prepared with prepare_v2() */ + bft usesAltMap:1; /* True if uses VdbeCursor.aAltMap[] */ yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */ yDbMask lockMask; /* Subset of btreeMask that requires a lock */ u32 aCounter[5]; /* Counters used by sqlite3_stmt_status() */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index cf062cf01d..fccd0e9536 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -618,6 +618,13 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ } if( pOp==p->aOp ) break; pOp--; + + if( p->usesAltMap==0 + && pOp[0].opcode==OP_Column && pOp[1].opcode==OP_Column + && pOp[0].p1==pOp[1].p1 && pOp[0].p2>=pOp[1].p2 + ){ + pOp->p5 |= OPFLAG_CONTINUE; + } } sqlite3DbFree(p->db, pParse->aLabel); pParse->aLabel = 0; @@ -4557,6 +4564,12 @@ void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){ } } +/* +** Set the "uses-alt-map" flag. +*/ +void sqlite3VdbeUsesAltMap(Vdbe *v){ + v->usesAltMap = 1; +} #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored diff --git a/src/wherecode.c b/src/wherecode.c index 4fd5e16fac..498ef48698 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -1003,6 +1003,7 @@ static void codeDeferredSeek( } sqlite3VdbeChangeP4(v, -1, (char*)ai, P4_INTARRAY); } + sqlite3VdbeUsesAltMap(v); } }