mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-18 10:21:03 +03:00
Improved query optimization for multi-column indexes where the second or
later columns are constrained by an IN operator and the earlier index columns limit the search to a small number of rows. Use the new OP_SeekScan opcode which does scanning of the relevant range of the index but gives up and falls back to doing a seek if the number of rows scanned grows to large, in order to guard against pathological cases where the estimated number of rows to be scanned is far too small. FossilOrigin-Name: 4a43430fd23f88352c33b29c4c105b72f6dc821f94bf362040c41a1648c402e5
This commit is contained in:
@@ -570,7 +570,7 @@ static int codeEqualityTerm(
|
||||
if( pLevel->u.in.nIn==0 ){
|
||||
pLevel->addrNxt = sqlite3VdbeMakeLabel(pParse);
|
||||
}
|
||||
if( iEq>0 ){
|
||||
if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){
|
||||
pLoop->wsFlags |= WHERE_IN_EARLYOUT;
|
||||
}
|
||||
|
||||
@@ -608,7 +608,7 @@ static int codeEqualityTerm(
|
||||
pIn++;
|
||||
}
|
||||
}
|
||||
if( iEq>0 ){
|
||||
if( iEq>0 && (pLoop->wsFlags & WHERE_IN_SEEKSCAN)==0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_SeekHit, pLevel->iIdxCur, 0, iEq);
|
||||
}
|
||||
}else{
|
||||
@@ -1803,6 +1803,20 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
|
||||
op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev];
|
||||
assert( op!=0 );
|
||||
if( (pLoop->wsFlags & WHERE_IN_SEEKSCAN)!=0 ){
|
||||
assert( op==OP_SeekGE );
|
||||
assert( regBignull==0 );
|
||||
/* TUNING: The OP_SeekScan opcode seeks to reduce the number
|
||||
** of expensive seek operations by replacing a single seek with
|
||||
** 1 or more step operations. The question is, how many steps
|
||||
** should we try before giving up and going with a seek. The cost
|
||||
** of a seek is proportional to the logarithm of the of the number
|
||||
** of entries in the tree, so basing the number of steps to try
|
||||
** on the estimated number of rows in the btree seems like a good
|
||||
** guess. */
|
||||
sqlite3VdbeAddOp1(v, OP_SeekScan, (pIdx->aiRowLogEst[0]+9)/10);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
|
||||
VdbeCoverage(v);
|
||||
VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind );
|
||||
@@ -1904,7 +1918,7 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE );
|
||||
}
|
||||
|
||||
if( pLoop->wsFlags & WHERE_IN_EARLYOUT ){
|
||||
if( (pLoop->wsFlags & WHERE_IN_EARLYOUT)!=0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_SeekHit, iIdxCur, nEq, nEq);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user