1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-08 03:22:21 +03:00

Optimize queries that contain "WHERE rowid IN (x, y, z...)" by using an intkey btree to store the (x, y, z...) set instead of an index btree. (CVS 5760)

FossilOrigin-Name: 803a1736d56b3c07b8ad38715fe0e39196ecc507
This commit is contained in:
danielk1977
2008-10-02 13:50:55 +00:00
parent 0368072905
commit 41a05b7bee
5 changed files with 141 additions and 23 deletions

View File

@@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.394 2008/09/17 00:13:12 drh Exp $
** $Id: expr.c,v 1.395 2008/10/02 13:50:56 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -1214,11 +1214,13 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
if( eType==0 ){
int rMayHaveNull = 0;
eType = IN_INDEX_EPH;
if( prNotFound ){
*prNotFound = rMayHaveNull = ++pParse->nMem;
}else if( pX->pLeft->iColumn<0 && pX->pSelect==0 ){
eType = IN_INDEX_ROWID;
}
sqlite3CodeSubselect(pParse, pX, rMayHaveNull);
eType = IN_INDEX_EPH;
sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
}else{
pX->iTable = iTab;
}
@@ -1237,9 +1239,20 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
**
** The pExpr parameter describes the expression that contains the IN
** operator or subquery.
**
** If parameter isRowid is non-zero, then expression pExpr is guaranteed
** to be of the form "<rowid> IN (?, ?, ?)", where <rowid> is a reference
** to some integer key column of a table B-Tree. In this case, use an
** intkey B-Tree to store the set of IN(...) values instead of the usual
** (slower) variable length keys B-Tree.
*/
#ifndef SQLITE_OMIT_SUBQUERY
void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr, int rMayHaveNull){
void sqlite3CodeSubselect(
Parse *pParse,
Expr *pExpr,
int rMayHaveNull,
int isRowid
){
int testAddr = 0; /* One-time test address */
Vdbe *v = sqlite3GetVdbe(pParse);
if( v==0 ) return;
@@ -1267,12 +1280,13 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr, int rMayHaveNull){
char affinity;
KeyInfo keyInfo;
int addr; /* Address of OP_OpenEphemeral instruction */
Expr *pLeft = pExpr->pLeft;
if( rMayHaveNull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull);
}
affinity = sqlite3ExprAffinity(pExpr->pLeft);
affinity = sqlite3ExprAffinity(pLeft);
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
** expression it is handled the same way. A virtual table is
@@ -1288,7 +1302,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr, int rMayHaveNull){
** is used.
*/
pExpr->iTable = pParse->nTab++;
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, 1);
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1;
@@ -1301,6 +1315,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr, int rMayHaveNull){
SelectDest dest;
ExprList *pEList;
assert( !isRowid );
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
dest.affinity = (int)affinity;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
@@ -1351,14 +1366,23 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr, int rMayHaveNull){
r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);
assert( pParse->disableColCache>0 );
pParse->disableColCache--;
sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
sqlite3ExprCacheAffinityChange(pParse, r3, 1);
sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);
if( isRowid ){
sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, sqlite3VdbeCurrentAddr(v)+2);
sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3);
}else{
sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
sqlite3ExprCacheAffinityChange(pParse, r3, 1);
sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);
}
}
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempReg(pParse, r2);
}
sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_KEYINFO);
if( !isRowid ){
sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_KEYINFO);
}
break;
}
@@ -2026,7 +2050,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
testcase( op==TK_EXISTS );
testcase( op==TK_SELECT );
if( pExpr->iColumn==0 ){
sqlite3CodeSubselect(pParse, pExpr, 0);
sqlite3CodeSubselect(pParse, pExpr, 0, 0);
}
inReg = pExpr->iColumn;
break;
@@ -2109,7 +2133,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
sqlite3VdbeJumpHere(v, j3);
/* Copy the value of register rNotFound (which is either NULL or 0)
** into the target register. This will be the result of the
** into the target register. This will be the result of the
** expression.
*/
sqlite3VdbeAddOp2(v, OP_Copy, rNotFound, target);