Optimize simple min() and max() queries. (CVS 382)

FossilOrigin-Name: cc5abfe392bdb8c3ed00e0610bc2b41851bfc9d7
This commit is contained in:
drh 2002-02-19 15:00:07 +00:00
parent aaab5725db
commit 9562b55115
7 changed files with 287 additions and 130 deletions

View File

@ -1,5 +1,5 @@
C Change\sthe\sname\sof\sthe\ssanity_check\sPRAGMA\sto\s"integrity_check"\sand\smake\nit\savailable\son\sall\scompiles.\s(CVS\s381)
D 2002-02-19T13:39:21
C Optimize\ssimple\smin()\sand\smax()\squeries.\s(CVS\s382)
D 2002-02-19T15:00:07
F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
F Makefile.template 3372d45f8853afdb70bd30cc6fb50a3cd9069834
F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@ -19,8 +19,8 @@ F ltmain.sh e9ed72eb1d690f447c13945eaf69e28af531eda1
F publish.sh 5b59f4aff037aafa0e4a3b6fa599495dbd73f360
F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9
F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
F src/btree.c 715209d8fff117d2e3024134c5b626f440fb0395
F src/btree.h 9fd16f33b9f2efe733fecff7ca000d2950a74d9f
F src/btree.c 8256ea416850fbd2af0ae50779b1a4b604de13c2
F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
F src/build.c 088acf87a92b00edda1206ccafac3518660b1b3b
F src/delete.c f8ad71be53cf18656b6573de65395852fe817f0c
F src/expr.c 7aff65ea0732b07d36925087ad611019103ad69a
@ -36,7 +36,7 @@ F src/pager.h b28f004e2f5541dc60cc32db01bf80cf4d056283
F src/parse.y b82278917959eefd05bd08c90e07a4fa5917ea51
F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
F src/select.c d2bbaf4cba97b4c40503d0dc47e8b729e7088e0b
F src/select.c 6dadbd3ba1e86334c9af321b48f6e3df1992f602
F src/shell.c c102dfe388c7618a668c944ff157c49cb48f28e3
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
F src/sqlite.h.in f57074c84a2c112a5093ba7a9d9636aa9cacc87c
@ -50,8 +50,8 @@ F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
F src/tokenize.c 9e98f94469694a763992860596137e78dbae0cc0
F src/update.c 95459f94a061860bf8e5716b3426a5ba85c79103
F src/util.c f31f3d6198a0d1296a16f5a6ceec423a932cbbf6
F src/vdbe.c 3c788341b581c9381ab2ecd4868041ed57ff27ad
F src/vdbe.h 20a662572485329cb0a6b648bf7c8cb6baec401d
F src/vdbe.c 2b03a7d39f05321e5570373cb2f3734c3cf86b70
F src/vdbe.h b4d35e159fbb80a74728b4a96e5b789fffce6f57
F src/where.c f79bc3179379b46b131a67ab10713779368dceee
F test/all.test 7a8a8a7a579ed2bb4d8976d55402f21eacd58049
F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
@ -124,7 +124,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
P 72c5a92aa6e3ae712af152cff8d1dc5b997b538e
R 50515068ff6057399f03cf57fa91cbb8
P c6e9048e66c8d8e2d5f6c62aa724eef3e9d9f572
R 41f437c3e65a91e5a2a52b6609362036
U drh
Z 763c5eb79aff590e79bd0703f9429a9c
Z ee034e966e6d17b9655294654ff0765f

View File

@ -1 +1 @@
c6e9048e66c8d8e2d5f6c62aa724eef3e9d9f572
cc5abfe392bdb8c3ed00e0610bc2b41851bfc9d7

View File

@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.53 2002/02/19 13:39:22 drh Exp $
** $Id: btree.c,v 1.54 2002/02/19 15:00:07 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@ -1325,6 +1325,30 @@ int sqliteBtreeFirst(BtCursor *pCur, int *pRes){
return rc;
}
/* Move the cursor to the last entry in the table. Return SQLITE_OK
** on success. Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty and there is no first element.
*/
int sqliteBtreeLast(BtCursor *pCur, int *pRes){
int rc;
Pgno pgno;
if( pCur->pPage==0 ) return SQLITE_ABORT;
rc = moveToRoot(pCur);
if( rc ) return rc;
if( pCur->pPage->nCell==0 ){
*pRes = 1;
return SQLITE_OK;
}
*pRes = 0;
while( (pgno = pCur->pPage->u.hdr.rightChild)!=0 ){
rc = moveToChild(pCur, pgno);
if( rc ) return rc;
}
pCur->idx = pCur->pPage->nCell-1;
pCur->bSkipNext = 0;
return rc;
}
/* Move the cursor so that it points to an entry near pKey.
** Return a success code.
**

View File

@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description
** of what each interface routine does.
**
** @(#) $Id: btree.h,v 1.23 2002/02/19 13:39:22 drh Exp $
** @(#) $Id: btree.h,v 1.24 2002/02/19 15:00:08 drh Exp $
*/
#ifndef _BTREE_H_
#define _BTREE_H_
@ -43,6 +43,7 @@ int sqliteBtreeDelete(BtCursor*);
int sqliteBtreeInsert(BtCursor*, const void *pKey, int nKey,
const void *pData, int nData);
int sqliteBtreeFirst(BtCursor*, int *pRes);
int sqliteBtreeLast(BtCursor*, int *pRes);
int sqliteBtreeNext(BtCursor*, int *pRes);
int sqliteBtreeKeySize(BtCursor*, int *pSize);
int sqliteBtreeKey(BtCursor*, int offset, int amt, char *zBuf);

View File

@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle SELECT statements in SQLite.
**
** $Id: select.c,v 1.61 2002/02/18 03:21:46 drh Exp $
** $Id: select.c,v 1.62 2002/02/19 15:00:08 drh Exp $
*/
#include "sqliteInt.h"
@ -710,6 +710,102 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
return 0;
}
/*
** Analyze the SELECT statement passed in as an argument to see if it
** is a simple min() or max() query. If it is and this query can be
** satisfied using a single seek to the beginning or end of an index,
** then generate the code for this SELECT return 1. If this is not a
** simple min() or max() query, then return 0;
**
** A simply min() or max() query looks like this:
**
** SELECT min(a) FROM table;
** SELECT max(a) FROM table;
**
** The query may have only a single table in its FROM argument. There
** can be no GROUP BY or HAVING or WHERE clauses. The result set must
** be the min() or max() of a single column of the table. The column
** in the min() or max() function must be indexed.
**
** The parameters to this routine are the same as for sqliteSelect().
** See the header comment on that routine for additional information.
*/
static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
Expr *pExpr;
int iCol;
Table *pTab;
Index *pIdx;
int base;
Vdbe *v;
int openOp;
int seekOp;
int cont;
ExprList eList;
struct ExprList_item eListItem;
/* Check to see if this query is a simple min() or max() query. Return
** zero if it is not.
*/
if( p->pGroupBy || p->pHaving || p->pWhere ) return 0;
if( p->pSrc->nId!=1 ) return 0;
if( p->pEList->nExpr!=1 ) return 0;
pExpr = p->pEList->a[0].pExpr;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
if( pExpr->pList==0 || pExpr->pList->nExpr!=1 ) return 0;
if( pExpr->iColumn!=FN_Min && pExpr->iColumn!=FN_Max ) return 0;
seekOp = pExpr->iColumn==FN_Min ? OP_Rewind : OP_Last;
pExpr = pExpr->pList->a[0].pExpr;
if( pExpr->op!=TK_COLUMN ) return 0;
iCol = pExpr->iColumn;
pTab = p->pSrc->a[0].pTab;
/* If we get to here, it means the query is of the correct form.
** Check to make sure we have an index.
*/
if( iCol<0 ){
pIdx = 0;
}else{
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pIdx->nColumn>=1 );
if( pIdx->aiColumn[0]==iCol ) break;
}
if( pIdx==0 ) return 0;
}
/* Identify column names if we will be using in the callback. This
** step is skipped if the output is going to a table or a memory cell.
*/
v = sqliteGetVdbe(pParse);
if( v==0 ) return 0;
if( eDest==SRT_Callback ){
generateColumnNames(pParse, p->pSrc, p->pEList);
}
/* Begin generating code
*/
base = pParse->nTab;
eList.nExpr = 1;
memset(&eListItem, 0, sizeof(eListItem));
eList.a = &eListItem;
eList.a[0].pExpr = pExpr;
openOp = pTab->isTemp ? OP_OpenAux : OP_Open;
sqliteVdbeAddOp(v, openOp, base, pTab->tnum);
if( pIdx==0 ){
sqliteVdbeAddOp(v, seekOp, base, 0);
}else{
sqliteVdbeAddOp(v, openOp, base+1, pIdx->tnum);
sqliteVdbeAddOp(v, seekOp, base+1, 0);
sqliteVdbeAddOp(v, OP_IdxRecno, base+1, 0);
sqliteVdbeAddOp(v, OP_Close, base+1, 0);
sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
}
cont = sqliteVdbeMakeLabel(v);
selectInnerLoop(pParse, &eList, base, 1, 0, -1, eDest, iParm, cont, cont);
sqliteVdbeResolveLabel(v, cont);
sqliteVdbeAddOp(v, OP_Close, base, 0);
return 1;
}
/*
** Generate code for the given SELECT statement.
**
@ -911,6 +1007,13 @@ int sqliteSelect(
}
}
/* Check for the special case of a min() or max() function by itself
** in the result set.
*/
if( simpleMinMaxQuery(pParse, p, eDest, iParm) ){
goto select_end;
}
/* Begin generating code.
*/
v = sqliteGetVdbe(pParse);

View File

@ -30,7 +30,7 @@
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.118 2002/02/19 13:39:23 drh Exp $
** $Id: vdbe.c,v 1.119 2002/02/19 15:00:08 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@ -866,29 +866,30 @@ static char *zOpName[] = { 0,
"Close", "MoveTo", "NewRecno", "PutIntKey",
"PutStrKey", "Distinct", "Found", "NotFound",
"IsUnique", "NotExists", "Delete", "Column",
"KeyAsData", "Recno", "FullKey", "Rewind",
"Next", "Destroy", "Clear", "CreateIndex",
"CreateTable", "IntegrityCk", "IdxPut", "IdxDelete",
"IdxRecno", "IdxGT", "IdxGE", "MemLoad",
"MemStore", "ListWrite", "ListRewind", "ListRead",
"ListReset", "SortPut", "SortMakeRec", "SortMakeKey",
"Sort", "SortNext", "SortCallback", "SortReset",
"FileOpen", "FileRead", "FileColumn", "AggReset",
"AggFocus", "AggIncr", "AggNext", "AggSet",
"AggGet", "SetInsert", "SetFound", "SetNotFound",
"MakeRecord", "MakeKey", "MakeIdxKey", "IncrKey",
"Goto", "If", "Halt", "ColumnCount",
"ColumnName", "Callback", "NullCallback", "Integer",
"String", "Pop", "Dup", "Pull",
"Push", "MustBeInt", "Add", "AddImm",
"Subtract", "Multiply", "Divide", "Remainder",
"BitAnd", "BitOr", "BitNot", "ShiftLeft",
"ShiftRight", "AbsValue", "Precision", "Min",
"Max", "Like", "Glob", "Eq",
"Ne", "Lt", "Le", "Gt",
"Ge", "IsNull", "NotNull", "Negative",
"And", "Or", "Not", "Concat",
"Noop", "Strlen", "Substr", "Limit",
"KeyAsData", "Recno", "FullKey", "Last",
"Rewind", "Next", "Destroy", "Clear",
"CreateIndex", "CreateTable", "IntegrityCk", "IdxPut",
"IdxDelete", "IdxRecno", "IdxGT", "IdxGE",
"MemLoad", "MemStore", "ListWrite", "ListRewind",
"ListRead", "ListReset", "SortPut", "SortMakeRec",
"SortMakeKey", "Sort", "SortNext", "SortCallback",
"SortReset", "FileOpen", "FileRead", "FileColumn",
"AggReset", "AggFocus", "AggIncr", "AggNext",
"AggSet", "AggGet", "SetInsert", "SetFound",
"SetNotFound", "MakeRecord", "MakeKey", "MakeIdxKey",
"IncrKey", "Goto", "If", "Halt",
"ColumnCount", "ColumnName", "Callback", "NullCallback",
"Integer", "String", "Pop", "Dup",
"Pull", "Push", "MustBeInt", "Add",
"AddImm", "Subtract", "Multiply", "Divide",
"Remainder", "BitAnd", "BitOr", "BitNot",
"ShiftLeft", "ShiftRight", "AbsValue", "Precision",
"Min", "Max", "Like", "Glob",
"Eq", "Ne", "Lt", "Le",
"Gt", "Ge", "IsNull", "NotNull",
"Negative", "And", "Or", "Not",
"Concat", "Noop", "Strlen", "Substr",
"Limit",
};
/*
@ -3096,7 +3097,11 @@ case OP_Column: {
/* Figure out how many bytes in the column data and where the column
** data begins.
*/
if( payloadSize<256 ){
if( payloadSize==0 ){
aStack[tos].flags = STK_Null;
p->tos = tos;
break;
}else if( payloadSize<256 ){
idxWidth = 1;
}else if( payloadSize<65536 ){
idxWidth = 2;
@ -3216,6 +3221,29 @@ case OP_FullKey: {
break;
}
/* Opcode: Last P1 P2 *
**
** The next use of the Recno or Column or Next instruction for P1
** will refer to the last entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
*/
case OP_Last: {
int i = pOp->p1;
BtCursor *pCrsr;
if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
int res;
sqliteBtreeLast(pCrsr, &res);
p->aCsr[i].atFirst = res==0;
if( res && pOp->p2>0 ){
pc = pOp->p2 - 1;
}
}
break;
}
/* Opcode: Rewind P1 P2 *
**
** The next use of the Recno or Column or Next instruction for P1

View File

@ -15,7 +15,7 @@
** or VDBE. The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.42 2002/02/19 13:39:23 drh Exp $
** $Id: vdbe.h,v 1.43 2002/02/19 15:00:08 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@ -97,112 +97,113 @@ typedef struct VdbeOp VdbeOp;
#define OP_KeyAsData 25
#define OP_Recno 26
#define OP_FullKey 27
#define OP_Rewind 28
#define OP_Next 29
#define OP_Last 28
#define OP_Rewind 29
#define OP_Next 30
#define OP_Destroy 30
#define OP_Clear 31
#define OP_CreateIndex 32
#define OP_CreateTable 33
#define OP_IntegrityCk 34
#define OP_Destroy 31
#define OP_Clear 32
#define OP_CreateIndex 33
#define OP_CreateTable 34
#define OP_IntegrityCk 35
#define OP_IdxPut 35
#define OP_IdxDelete 36
#define OP_IdxRecno 37
#define OP_IdxGT 38
#define OP_IdxGE 39
#define OP_IdxPut 36
#define OP_IdxDelete 37
#define OP_IdxRecno 38
#define OP_IdxGT 39
#define OP_IdxGE 40
#define OP_MemLoad 40
#define OP_MemStore 41
#define OP_MemLoad 41
#define OP_MemStore 42
#define OP_ListWrite 42
#define OP_ListRewind 43
#define OP_ListRead 44
#define OP_ListReset 45
#define OP_ListWrite 43
#define OP_ListRewind 44
#define OP_ListRead 45
#define OP_ListReset 46
#define OP_SortPut 46
#define OP_SortMakeRec 47
#define OP_SortMakeKey 48
#define OP_Sort 49
#define OP_SortNext 50
#define OP_SortCallback 51
#define OP_SortReset 52
#define OP_SortPut 47
#define OP_SortMakeRec 48
#define OP_SortMakeKey 49
#define OP_Sort 50
#define OP_SortNext 51
#define OP_SortCallback 52
#define OP_SortReset 53
#define OP_FileOpen 53
#define OP_FileRead 54
#define OP_FileColumn 55
#define OP_FileOpen 54
#define OP_FileRead 55
#define OP_FileColumn 56
#define OP_AggReset 56
#define OP_AggFocus 57
#define OP_AggIncr 58
#define OP_AggNext 59
#define OP_AggSet 60
#define OP_AggGet 61
#define OP_AggReset 57
#define OP_AggFocus 58
#define OP_AggIncr 59
#define OP_AggNext 60
#define OP_AggSet 61
#define OP_AggGet 62
#define OP_SetInsert 62
#define OP_SetFound 63
#define OP_SetNotFound 64
#define OP_SetInsert 63
#define OP_SetFound 64
#define OP_SetNotFound 65
#define OP_MakeRecord 65
#define OP_MakeKey 66
#define OP_MakeIdxKey 67
#define OP_IncrKey 68
#define OP_MakeRecord 66
#define OP_MakeKey 67
#define OP_MakeIdxKey 68
#define OP_IncrKey 69
#define OP_Goto 69
#define OP_If 70
#define OP_Halt 71
#define OP_Goto 70
#define OP_If 71
#define OP_Halt 72
#define OP_ColumnCount 72
#define OP_ColumnName 73
#define OP_Callback 74
#define OP_NullCallback 75
#define OP_ColumnCount 73
#define OP_ColumnName 74
#define OP_Callback 75
#define OP_NullCallback 76
#define OP_Integer 76
#define OP_String 77
#define OP_Pop 78
#define OP_Dup 79
#define OP_Pull 80
#define OP_Push 81
#define OP_MustBeInt 82
#define OP_Integer 77
#define OP_String 78
#define OP_Pop 79
#define OP_Dup 80
#define OP_Pull 81
#define OP_Push 82
#define OP_MustBeInt 83
#define OP_Add 83
#define OP_AddImm 84
#define OP_Subtract 85
#define OP_Multiply 86
#define OP_Divide 87
#define OP_Remainder 88
#define OP_BitAnd 89
#define OP_BitOr 90
#define OP_BitNot 91
#define OP_ShiftLeft 92
#define OP_ShiftRight 93
#define OP_AbsValue 94
#define OP_Precision 95
#define OP_Min 96
#define OP_Max 97
#define OP_Like 98
#define OP_Glob 99
#define OP_Eq 100
#define OP_Ne 101
#define OP_Lt 102
#define OP_Le 103
#define OP_Gt 104
#define OP_Ge 105
#define OP_IsNull 106
#define OP_NotNull 107
#define OP_Negative 108
#define OP_And 109
#define OP_Or 110
#define OP_Not 111
#define OP_Concat 112
#define OP_Noop 113
#define OP_Add 84
#define OP_AddImm 85
#define OP_Subtract 86
#define OP_Multiply 87
#define OP_Divide 88
#define OP_Remainder 89
#define OP_BitAnd 90
#define OP_BitOr 91
#define OP_BitNot 92
#define OP_ShiftLeft 93
#define OP_ShiftRight 94
#define OP_AbsValue 95
#define OP_Precision 96
#define OP_Min 97
#define OP_Max 98
#define OP_Like 99
#define OP_Glob 100
#define OP_Eq 101
#define OP_Ne 102
#define OP_Lt 103
#define OP_Le 104
#define OP_Gt 105
#define OP_Ge 106
#define OP_IsNull 107
#define OP_NotNull 108
#define OP_Negative 109
#define OP_And 110
#define OP_Or 111
#define OP_Not 112
#define OP_Concat 113
#define OP_Noop 114
#define OP_Strlen 114
#define OP_Substr 115
#define OP_Strlen 115
#define OP_Substr 116
#define OP_Limit 116
#define OP_Limit 117
#define OP_MAX 116
#define OP_MAX 117
/*
** Prototypes for the VDBE interface. See comments on the implementation