From 1c2c0b776fdd1e12e7d844c8766157b82e4265a0 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 4 Jan 2014 19:27:05 +0000 Subject: [PATCH] Avoid redundant register loads during index key generation when doing a DELETE or INTEGRITY_CHECK on a table with multiple indices. FossilOrigin-Name: 8f6e6149a165f516be6395fd753e163d52ffd52e --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/build.c | 2 +- src/delete.c | 24 +++++++++++++++++++++--- src/pragma.c | 7 +++++-- src/sqliteInt.h | 2 +- src/where.c | 2 +- 7 files changed, 40 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index 6426172ac4..66e96c4c62 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Omit\sOP_Close\soperations\sthat\soccur\simmediately\sprior\sto\sOP_Halt\sand\swhich\ncannot\sbe\sjumped\sover. -D 2014-01-04T16:49:02.617 +C Avoid\sredundant\sregister\sloads\sduring\sindex\skey\sgeneration\swhen\sdoing\sa\nDELETE\sor\sINTEGRITY_CHECK\son\sa\stable\swith\smultiple\sindices. +D 2014-01-04T19:27:05.589 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -169,12 +169,12 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btree.c 11e29ef8cf16a42925fde036bcffbeffd9cc82df F src/btree.h a61ddebc78c66795a2b93181321a116746302cc9 F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0 -F src/build.c 5597ffa6d60759f89da3dd8a326c291a75e83c23 +F src/build.c 3609c8aa26947d7a035faa23eb1cb2cfc54b4680 F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 -F src/delete.c f7c47fbbcbddf83c4af5df3681aa05a741a8d536 +F src/delete.c 91e1321021db5dc266360531b8b6550009d771ff F src/expr.c 15a86b7632da09924ccffb53fafa86e7d8727b70 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 2ab0f5384b70594468ef3ac5c7ed8ca24bfd17d5 @@ -213,7 +213,7 @@ F src/parse.y acee1a9958539e21263362b194594c5255ad2fca F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c 57fee9a9a617218f5037afbbe49b09da65bde56b -F src/pragma.c 5ab7279d132143feb77f773688a24ab05da75fd7 +F src/pragma.c ed409ce4104cf4d9de6ead40ace70974f124853b F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337 F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269 F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece @@ -224,7 +224,7 @@ F src/shell.c a3541193d5fce37e91dad8ef46a9505aa7c9b344 F src/sqlite.h.in d94a8b89522f526ba711182ee161e06f8669bcc9 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h 40fa66cb72bc88bcd0a16967f4ad58cff7e2c4fd +F src/sqliteInt.h 672ef78e9e6f8b03fc9d37884f9784fb02e6ce2d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -293,7 +293,7 @@ F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74 -F src/where.c 8e3cb2030eaa242defb804aa30115b5d870e5cd4 +F src/where.c 18f07fd0fd116a5880773c689eb7cd8e60175107 F src/whereInt.h 96a75c61f1d2b9d4a8e4bb17d89deb0cf7cba358 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1148,7 +1148,7 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 4e725f53131d3584319c710c8710a068989543c6 -R 9d927180209ef7717259744d3fe6bde8 +P 874b7e9999811c288ad41d07709f88e458d2d497 +R fc5dbcd7a08b2e4b11ffb23dc1241ea1 U drh -Z 5260028c0eafa272f25baa07be63a049 +Z 86dc65664e674593ae8c26084106bce8 diff --git a/manifest.uuid b/manifest.uuid index eb18276f5b..cc46b176ca 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -874b7e9999811c288ad41d07709f88e458d2d497 \ No newline at end of file +8f6e6149a165f516be6395fd753e163d52ffd52e \ No newline at end of file diff --git a/src/build.c b/src/build.c index 5c8c9300f6..15430fd28b 100644 --- a/src/build.c +++ b/src/build.c @@ -2678,7 +2678,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); regRecord = sqlite3GetTempReg(pParse); - sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 0, &iPartIdxLabel); + sqlite3GenerateIndexKey(pParse,pIndex,iTab,regRecord,0,&iPartIdxLabel,0,0); sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord); sqlite3VdbeResolveLabel(v, iPartIdxLabel); sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1); diff --git a/src/delete.c b/src/delete.c index 641b4a763f..e448e47b02 100644 --- a/src/delete.c +++ b/src/delete.c @@ -716,9 +716,10 @@ void sqlite3GenerateRowIndexDelete( int *aRegIdx /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */ ){ int i; /* Index loop counter */ - int r1; /* Register holding an index key */ + int r1 = -1; /* Register holding an index key */ int iPartIdxLabel; /* Jump destination for skipping partial index entries */ Index *pIdx; /* Current index */ + Index *pPrior = 0; /* Prior index */ Vdbe *v; /* The prepared statement under construction */ Index *pPk; /* PRIMARY KEY index, or NULL for rowid tables */ @@ -729,10 +730,12 @@ void sqlite3GenerateRowIndexDelete( if( aRegIdx!=0 && aRegIdx[i]==0 ) continue; if( pIdx==pPk ) continue; VdbeModuleComment((v, "GenRowIdxDel for %s", pIdx->zName)); - r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel); + r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, + &iPartIdxLabel, pPrior, r1); sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1, pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn); sqlite3VdbeResolveLabel(v, iPartIdxLabel); + pPrior = pIdx; } } @@ -754,6 +757,17 @@ void sqlite3GenerateRowIndexDelete( ** to false or null. If pIdx is not a partial index, *piPartIdxLabel ** will be set to zero which is an empty label that is ignored by ** sqlite3VdbeResolveLabel(). +** +** The pPrior and regPrior parameters are used to implement a cache to +** avoid unnecessary register loads. If pPrior is not NULL, then it is +** a pointer to a different index for which an index key has just been +** computed into register regPrior. If the current pIdx index is generating +** its key into the same sequence of registers and if pPrior and pIdx share +** a column in common, then the register corresponding to that column already +** holds the correct value and the loading of that register is skipped. +** This optimization is helpful when doing a DELETE or an INTEGRITY_CHECK +** on a table with multiple indices, and especially with the ROWID or +** PRIMARY KEY columns of the index. */ int sqlite3GenerateIndexKey( Parse *pParse, /* Parsing context */ @@ -761,7 +775,9 @@ int sqlite3GenerateIndexKey( int iDataCur, /* Cursor number from which to take column data */ int regOut, /* Put the new key into this register if not 0 */ int prefixOnly, /* Compute only a unique prefix of the key */ - int *piPartIdxLabel /* OUT: Jump to this label to skip partial index */ + int *piPartIdxLabel, /* OUT: Jump to this label to skip partial index */ + Index *pPrior, /* Previously generated index key */ + int regPrior /* Register holding previous generated key */ ){ Vdbe *v = pParse->pVdbe; int j; @@ -781,7 +797,9 @@ int sqlite3GenerateIndexKey( } nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn; regBase = sqlite3GetTempRange(pParse, nCol); + if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0; for(j=0; jaiColumn[j]==pIdx->aiColumn[j] ) continue; sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j], regBase+j); /* If the column affinity is REAL but the number is an integer, then it diff --git a/src/pragma.c b/src/pragma.c index bbd27b8c18..7383bce96f 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1881,8 +1881,10 @@ void sqlite3Pragma( for(x=sqliteHashFirst(pTbls); x && !isQuick; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx, *pPk; + Index *pPrior = 0; int loopTop; int iDataCur, iIdxCur; + int r1 = -1; if( pTab->pIndex==0 ) continue; pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab); @@ -1901,9 +1903,10 @@ void sqlite3Pragma( loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int jmp2, jmp3, jmp4; - int r1; if( pPk==pIdx ) continue; - r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3); + r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, + pPrior, r1); + pPrior = pIdx; sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */ jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, 0, r1, pIdx->nColumn); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 035e590bfe..d3e993c135 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2992,7 +2992,7 @@ int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); int sqlite3IsRowid(const char*); void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*); -int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*); +int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*,Index*,int); void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, u8,u8,int,int*); void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int); diff --git a/src/where.c b/src/where.c index 0acc0db53f..d5444a6054 100644 --- a/src/where.c +++ b/src/where.c @@ -1710,7 +1710,7 @@ static void constructAutomaticIndex( /* Fill the automatic index with content */ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); regRecord = sqlite3GetTempReg(pParse); - sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0); + sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0); sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1);