When using an index on an expression, try to use the columns of the index
rather than pulling columns from the table and reevaluating the expression. FossilOrigin-Name: a47efb7c8520a01110ce3b3531ebe1bab6720780d67fba001992c44c5807d332
This commit is contained in:
commit
d6e992cb1e
23
manifest
23
manifest
@ -1,5 +1,5 @@
|
||||
C Smaller\sand\sfaster\svdbeFreeOpArray()
|
||||
D 2017-04-10T20:51:21.112
|
||||
C When\susing\san\sindex\son\san\sexpression,\stry\sto\suse\sthe\scolumns\sof\sthe\sindex\nrather\sthan\spulling\scolumns\sfrom\sthe\stable\sand\sreevaluating\sthe\sexpression.
|
||||
D 2017-04-11T01:30:42.675
|
||||
F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc a4c0613a18663bda56d8cf76079ab6590a7c3602e54befb4bbdef76bcaa38b6a
|
||||
@ -354,7 +354,7 @@ F src/ctime.c 47d91a25ad8f199a71a5b1b7b169d6dd0d6e98c5719eca801568798743d1161c
|
||||
F src/date.c ee676e7694dfadbdd2fde1a258a71be8360ba5ae
|
||||
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
|
||||
F src/delete.c 0d9d5549d42e79ce4d82ff1db1e6c81e36d2f67c
|
||||
F src/expr.c 6bce2cbdd822963cf28e782938a96274cc37f18ac28dec7a4e35ccac09f66ce8
|
||||
F src/expr.c 8fd6b7bc10c2c33e017b0f2715efdc83c01e348be27797022ed9eaa3002ca720
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c 2e9aabe1aee76273aff8a84ee92c464e095400ae
|
||||
F src/func.c 9d52522cc8ae7f5cdadfe14594262f1618bc1f86083c4cd6da861b4cf5af6174
|
||||
@ -401,12 +401,12 @@ F src/printf.c 8757834f1b54dae512fb25eb1acc8e94a0d15dd2290b58f2563f65973265adb2
|
||||
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
|
||||
F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
|
||||
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
|
||||
F src/select.c afcf31d8ed7c890328a31d3f350467ccd273af345b24562382b398d6d9cd0664
|
||||
F src/select.c 9228235fdefe6de138ac01c4c68d07fd95d78780ef85112a76e63e260a6f5897
|
||||
F src/shell.c 70f4957b988572315e97c56941fdc81fd35907fee36b7b2e7be5ec4c7e9d065d
|
||||
F src/sqlite.h.in 40233103e3e4e10f8a63523498d0259d232e42aba478e2d3fb914799185aced6
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28
|
||||
F src/sqliteInt.h 6cf244eb06119b44e155717708e54f0638c35e9bd8ef59ea570eb1f093f0da44
|
||||
F src/sqliteInt.h 9affb53bb405dcea1d86e85198ebaf6232a684cc2b2af6b3c181869f1c8f3e93
|
||||
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
|
||||
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
|
||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||
@ -482,9 +482,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||
F src/wal.c 40c543f0a2195d1b0dc88ef12142bea690009344
|
||||
F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
|
||||
F src/walker.c b71a992b413b3a022572eccf29ef4b4890223791
|
||||
F src/where.c 49b48b720184fdde747c468d7270feeb1b88c6a71092cea3a1aa168dc8ac0b0f
|
||||
F src/whereInt.h 2d50c2b74a33be44cb68fdecee30b4d93552f1f4
|
||||
F src/wherecode.c 677e95413c472c0b413023b6b69a47f40fce1b04
|
||||
F src/where.c 1d14e18f32231fa7969e718e7b60ef749b0065e2a7e1b6b00883b20732d280f1
|
||||
F src/whereInt.h 7a21ef633e26acbf46df04add2eba6e0a2100c78dc5879049e93f981fc3344df
|
||||
F src/wherecode.c 943e32e9dccd0af802e0683ae11071c8bd808364e5908a5fb66758bd404c8681
|
||||
F src/whereexpr.c 130cdd1a43af71b19755270fb1224874cf55158c
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
@ -1570,7 +1570,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P efd1702ae8da8e0dd3d2ee7bd5a1bd8aeff2b370498e404041fcb406fdaf72e4
|
||||
R 08e07e2df33f53e5c795c66423297623
|
||||
P e052436d9f54b785facd661adc648512356b831c0547aa8f347ebf4bd8ef1254 c59eaf2b7cd2596733f349fc0fe979f71fd29bd73152a0c57066e0b69d5b7a4a
|
||||
R 1b0a9c05391f59848f876fd33c1876bb
|
||||
T +closed c59eaf2b7cd2596733f349fc0fe979f71fd29bd73152a0c57066e0b69d5b7a4a
|
||||
U drh
|
||||
Z fe1f0eec29c92bb8a2e730e35a741ada
|
||||
Z d8fc420323e8e66f4fe145abb4c72eca
|
||||
|
@ -1 +1 @@
|
||||
e052436d9f54b785facd661adc648512356b831c0547aa8f347ebf4bd8ef1254
|
||||
a47efb7c8520a01110ce3b3531ebe1bab6720780d67fba001992c44c5807d332
|
@ -3192,6 +3192,10 @@ void sqlite3ExprCodeGetColumnOfTable(
|
||||
int iCol, /* Index of the column to extract */
|
||||
int regOut /* Extract the value into this register */
|
||||
){
|
||||
if( pTab==0 ){
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
|
||||
return;
|
||||
}
|
||||
if( iCol<0 || iCol==pTab->iPKey ){
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
|
||||
}else{
|
||||
|
29
src/select.c
29
src/select.c
@ -1530,6 +1530,7 @@ static void generateColumnTypes(
|
||||
NameContext sNC;
|
||||
sNC.pSrcList = pTabList;
|
||||
sNC.pParse = pParse;
|
||||
sNC.pNext = 0;
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
Expr *p = pEList->a[i].pExpr;
|
||||
const char *zType;
|
||||
@ -1554,6 +1555,19 @@ static void generateColumnTypes(
|
||||
#endif /* !defined(SQLITE_OMIT_DECLTYPE) */
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the Table objecct in the SrcList that has cursor iCursor.
|
||||
** Or return NULL if no such Table object exists in the SrcList.
|
||||
*/
|
||||
static Table *tableWithCursor(SrcList *pList, int iCursor){
|
||||
int j;
|
||||
for(j=0; j<pList->nSrc; j++){
|
||||
if( pList->a[j].iCursor==iCursor ) return pList->a[j].pTab;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Generate code that will tell the VDBE the names of columns
|
||||
** in the result set. This information is used to provide the
|
||||
@ -1565,7 +1579,8 @@ static void generateColumnNames(
|
||||
ExprList *pEList /* Expressions defining the result set */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int i, j;
|
||||
int i;
|
||||
Table *pTab;
|
||||
sqlite3 *db = pParse->db;
|
||||
int fullNames, shortNames;
|
||||
|
||||
@ -1590,15 +1605,11 @@ static void generateColumnNames(
|
||||
if( pEList->a[i].zName ){
|
||||
char *zName = pEList->a[i].zName;
|
||||
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
|
||||
}else if( p->op==TK_COLUMN || p->op==TK_AGG_COLUMN ){
|
||||
Table *pTab;
|
||||
}else if( (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN)
|
||||
&& (pTab = tableWithCursor(pTabList, p->iTable))!=0
|
||||
){
|
||||
char *zCol;
|
||||
int iCol = p->iColumn;
|
||||
for(j=0; ALWAYS(j<pTabList->nSrc); j++){
|
||||
if( pTabList->a[j].iCursor==p->iTable ) break;
|
||||
}
|
||||
assert( j<pTabList->nSrc );
|
||||
pTab = pTabList->a[j].pTab;
|
||||
if( iCol<0 ) iCol = pTab->iPKey;
|
||||
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
|
||||
if( iCol<0 ){
|
||||
@ -3147,7 +3158,7 @@ static void substSelect(Parse*, Select *, int, ExprList*, int);
|
||||
** This routine is part of the flattening procedure. A subquery
|
||||
** whose result set is defined by pEList appears as entry in the
|
||||
** FROM clause of a SELECT such that the VDBE cursor assigned to that
|
||||
** FORM clause entry is iTable. This routine make the necessary
|
||||
** FORM clause entry is iTable. This routine makes the necessary
|
||||
** changes to pExpr so that it refers directly to the source table
|
||||
** of the subquery rather the result set of the subquery.
|
||||
*/
|
||||
|
@ -3324,6 +3324,7 @@ struct Walker {
|
||||
struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
|
||||
int *aiCol; /* array of column indexes */
|
||||
struct IdxCover *pIdxCover; /* Check for index coverage */
|
||||
struct IdxExprTrans *pIdxTrans; /* Convert indexed expr to column */
|
||||
} u;
|
||||
};
|
||||
|
||||
|
@ -4447,6 +4447,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
pWInfo->pParse = pParse;
|
||||
pWInfo->pTabList = pTabList;
|
||||
pWInfo->pOrderBy = pOrderBy;
|
||||
pWInfo->pWhere = pWhere;
|
||||
pWInfo->pResultSet = pResultSet;
|
||||
pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
|
||||
pWInfo->nLevel = nTabList;
|
||||
|
@ -417,6 +417,7 @@ struct WhereInfo {
|
||||
SrcList *pTabList; /* List of tables in the join */
|
||||
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
|
||||
ExprList *pResultSet; /* Result set of the query */
|
||||
Expr *pWhere; /* The complete WHERE clause */
|
||||
LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
|
||||
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
|
||||
int iContinue; /* Jump here to continue with next record */
|
||||
|
@ -1039,6 +1039,69 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
|
||||
}
|
||||
}
|
||||
|
||||
/* An instance of the IdxExprTrans object carries information about a
|
||||
** mapping from an expression on table columns into a column in an index
|
||||
** down through the Walker.
|
||||
*/
|
||||
typedef struct IdxExprTrans {
|
||||
Expr *pIdxExpr; /* The index expression */
|
||||
int iTabCur; /* The cursor of the corresponding table */
|
||||
int iIdxCur; /* The cursor for the index */
|
||||
int iIdxCol; /* The column for the index */
|
||||
} IdxExprTrans;
|
||||
|
||||
/* The walker node callback used to transform matching expressions into
|
||||
** a reference to an index column for an index on an expression.
|
||||
**
|
||||
** If pExpr matches, then transform it into a reference to the index column
|
||||
** that contains the value of pExpr.
|
||||
*/
|
||||
static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
|
||||
IdxExprTrans *pX = p->u.pIdxTrans;
|
||||
if( sqlite3ExprCompare(pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
|
||||
pExpr->op = TK_COLUMN;
|
||||
pExpr->iTable = pX->iIdxCur;
|
||||
pExpr->iColumn = pX->iIdxCol;
|
||||
pExpr->pTab = 0;
|
||||
return WRC_Prune;
|
||||
}else{
|
||||
return WRC_Continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** For an indexes on expression X, locate every instance of expression X in pExpr
|
||||
** and change that subexpression into a reference to the appropriate column of
|
||||
** the index.
|
||||
*/
|
||||
static void whereIndexExprTrans(
|
||||
Index *pIdx, /* The Index */
|
||||
int iTabCur, /* Cursor of the table that is being indexed */
|
||||
int iIdxCur, /* Cursor of the index itself */
|
||||
WhereInfo *pWInfo /* Transform expressions in this WHERE clause */
|
||||
){
|
||||
int iIdxCol; /* Column number of the index */
|
||||
ExprList *aColExpr; /* Expressions that are indexed */
|
||||
Walker w;
|
||||
IdxExprTrans x;
|
||||
aColExpr = pIdx->aColExpr;
|
||||
if( aColExpr==0 ) return; /* Not an index on expressions */
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.xExprCallback = whereIndexExprTransNode;
|
||||
w.u.pIdxTrans = &x;
|
||||
x.iTabCur = iTabCur;
|
||||
x.iIdxCur = iIdxCur;
|
||||
for(iIdxCol=0; iIdxCol<aColExpr->nExpr; iIdxCol++){
|
||||
if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue;
|
||||
assert( aColExpr->a[iIdxCol].pExpr!=0 );
|
||||
x.iIdxCol = iIdxCol;
|
||||
x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
|
||||
sqlite3WalkExpr(&w, pWInfo->pWhere);
|
||||
sqlite3WalkExprList(&w, pWInfo->pOrderBy);
|
||||
sqlite3WalkExprList(&w, pWInfo->pResultSet);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code for the start of the iLevel-th loop in the WHERE clause
|
||||
** implementation described by pWInfo.
|
||||
@ -1620,6 +1683,13 @@ Bitmask sqlite3WhereCodeOneLoopStart(
|
||||
iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
/* If pIdx is an index on one or more expressions, then look through
|
||||
** all the expressions in pWInfo and try to transform matching expressions
|
||||
** into reference to index columns.
|
||||
*/
|
||||
whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
|
||||
|
||||
|
||||
/* Record the instruction used to terminate the loop. */
|
||||
if( pLoop->wsFlags & WHERE_ONEROW ){
|
||||
pLevel->op = OP_Noop;
|
||||
|
Loading…
x
Reference in New Issue
Block a user