mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-12 13:01:09 +03:00
Avoid redundant register loads during index key generation when doing a
DELETE or INTEGRITY_CHECK on a table with multiple indices. FossilOrigin-Name: 8f6e6149a165f516be6395fd753e163d52ffd52e
This commit is contained in:
24
src/delete.c
24
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; j<nCol; j++){
|
||||
if( pPrior && pPrior->aiColumn[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
|
||||
|
||||
Reference in New Issue
Block a user