Avoid storing redundant fields in sorter records when the sort-key

and data have fields in common.

FossilOrigin-Name: b835cf3e507b910b6a3e0f802ce2c40a72d0c227
This commit is contained in:
drh 2016-11-11 19:08:00 +00:00
commit 66adb0a848
5 changed files with 66 additions and 28 deletions

View File

@ -1,5 +1,5 @@
C Enhance\sthe\sOP_IdxInsert\sopcode\sso\sthat\sit\scan\sused\sunpacked\skey\svalues\sif\nthey\sare\savailable.\s\sUpdate\sthe\scode\sgenerator\sto\stake\sadvantage\sof\sthis\nnew\scapability.\s\sThe\sspeedtest1.c\stest\sis\sabout\s2.6%\sfaster\sas\sa\sresult.
D 2016-11-11T19:01:11.983
C Avoid\sstoring\sredundant\sfields\sin\ssorter\srecords\swhen\sthe\ssort-key\s\nand\sdata\shave\sfields\sin\scommon.
D 2016-11-11T19:08:00.236
F Makefile.in 6fd48ffcf7c2deea7499062d1f3747f986c19678
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc e0217f2d35a0448abbe4b066132ae20136e8b408
@ -340,7 +340,7 @@ F src/ctime.c a2a52d6e353f459d8ab0f07321f60fafa47d5421
F src/date.c 95c9a8d00767e7221a8e9a31f4e913fc8029bf6b
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
F src/delete.c 6cac3a6c3f3c5ad4cacc402aee1610fc94ebc3dc
F src/expr.c ddd46bafbbd77b83c8daa733ebbe906093b558dc
F src/expr.c d8c8277d77e95d7fcce3b6b6d0f66652e482567f
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c b9ca262f6ad4d030a3cab737ebf9b0b3c8b4ac80
F src/func.c 7057bc2c105b82faa668d8e2ec85fad4540e5c51
@ -387,12 +387,12 @@ F src/printf.c a5f0ca08ddede803c241266abb46356ec748ded1
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/resolve.c bb070cf5f23611c44ab7e4788803684e385fc3fb
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c 0a7c523d755bcd39ae54f6a44bb66a7f0e1d89b3
F src/select.c 672b1af237ad257149fc5189f3277dcbca036eeb
F src/shell.c f04e4af75c5517735397d060ed0b4a874104bb41
F src/sqlite.h.in 803f7050f69b2eea573fac219f3c92582c096027
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae
F src/sqliteInt.h 37628fe30c464dc790bcee3bfd3d0caa8f222ed1
F src/sqliteInt.h 603953faca895386d4f3a8b7046f3e4e6c071c53
F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
@ -1532,8 +1532,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 46e0016207b8e7df2ae6c7491fd0f3c2926eed21 1a587d72f981cb7064cfd8916a52a83ad9ba6074
R d4149095f37aacb5dfcbf6f677226eee
T +closed 1a587d72f981cb7064cfd8916a52a83ad9ba6074
P 925840cfdb969a76640a1247cc4a7b2c0de5cb74 dd62d2de6eb12dc1902d6df050c395b1dcac01b4
R 710cd32b5d7d9f26ab9c8738e2187743
T +closed dd62d2de6eb12dc1902d6df050c395b1dcac01b4
U drh
Z 89ee46a4d9ea247735e0710261d136a5
Z 2fa3093086a563b78a5be35466f1815c

View File

@ -1 +1 @@
925840cfdb969a76640a1247cc4a7b2c0de5cb74
b835cf3e507b910b6a3e0f802ce2c40a72d0c227

View File

@ -4086,8 +4086,13 @@ int sqlite3ExprCodeExprList(
if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR;
for(pItem=pList->a, i=0; i<n; i++, pItem++){
Expr *pExpr = pItem->pExpr;
if( (flags & SQLITE_ECEL_REF)!=0 && (j = pList->a[i].u.x.iOrderByCol)>0 ){
sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
if( (flags & SQLITE_ECEL_REF)!=0 && (j = pItem->u.x.iOrderByCol)>0 ){
if( flags & SQLITE_ECEL_OMITREF ){
i--;
n--;
}else{
sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i);
}
}else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
}else{

View File

@ -521,7 +521,7 @@ static void pushOntoSorter(
int iLimit; /* LIMIT counter */
assert( bSeq==0 || bSeq==1 );
assert( nData==1 || regData==regOrigData );
assert( nData==1 || regData==regOrigData || regOrigData==0 );
if( nPrefixReg ){
assert( nPrefixReg==nExpr+bSeq );
regBase = regData - nExpr - bSeq;
@ -533,11 +533,11 @@ static void pushOntoSorter(
iLimit = pSelect->iOffset ? pSelect->iOffset+1 : pSelect->iLimit;
pSort->labelDone = sqlite3VdbeMakeLabel(v);
sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
SQLITE_ECEL_DUP|SQLITE_ECEL_REF);
SQLITE_ECEL_DUP | (regOrigData? SQLITE_ECEL_REF : 0));
if( bSeq ){
sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr);
}
if( nPrefixReg==0 ){
if( nPrefixReg==0 && nData>0 ){
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData);
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase+nOBSat, nBase-nOBSat, regRecord);
@ -667,7 +667,7 @@ static void codeDistinct(
** If srcTab is negative, then the pEList expressions
** are evaluated in order to get the data for this row. If srcTab is
** zero or more, then data is pulled from srcTab and pEList is used only
** to get number columns and the datatype for each column.
** to get the number of columns and the collation sequence for each column.
*/
static void selectInnerLoop(
Parse *pParse, /* The parser context */
@ -682,13 +682,20 @@ static void selectInnerLoop(
){
Vdbe *v = pParse->pVdbe;
int i;
int hasDistinct; /* True if the DISTINCT keyword is present */
int regResult; /* Start of memory holding result set */
int hasDistinct; /* True if the DISTINCT keyword is present */
int eDest = pDest->eDest; /* How to dispose of results */
int iParm = pDest->iSDParm; /* First argument to disposal method */
int nResultCol; /* Number of result columns */
int nPrefixReg = 0; /* Number of extra registers before regResult */
/* Usually, regResult is the first cell in an array of memory cells
** containing the current result row. In this case regOrig is set to the
** same value. However, if the results are being sent to the sorter, the
** values for any expressions that are also part of the sort-key are omitted
** from this array. In this case regOrig is set to zero. */
int regResult; /* Start of memory holding current results */
int regOrig; /* Start of memory holding full result (or 0) */
assert( v );
assert( pEList!=0 );
hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
@ -719,7 +726,7 @@ static void selectInnerLoop(
pParse->nMem += nResultCol;
}
pDest->nSdst = nResultCol;
regResult = pDest->iSdst;
regOrig = regResult = pDest->iSdst;
if( srcTab>=0 ){
for(i=0; i<nResultCol; i++){
sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i);
@ -735,7 +742,26 @@ static void selectInnerLoop(
}else{
ecelFlags = 0;
}
sqlite3ExprCodeExprList(pParse, pEList, regResult, 0, ecelFlags);
assert( eDest!=SRT_Table || pSort==0 );
if( pSort && hasDistinct==0 && eDest!=SRT_EphemTab ){
/* For each expression in pEList that is a copy of an expression in
** the ORDER BY clause (pSort->pOrderBy), set the associated
** iOrderByCol value to one more than the index of the ORDER BY
** expression within the sort-key that pushOntoSorter() will generate.
** This allows the pEList field to be omitted from the sorted record,
** saving space and CPU cycles. */
ecelFlags |= (SQLITE_ECEL_OMITREF|SQLITE_ECEL_REF);
for(i=pSort->nOBSat; i<pSort->pOrderBy->nExpr; i++){
int j;
if( (j = pSort->pOrderBy->a[i].u.x.iOrderByCol)>0 ){
pEList->a[j-1].u.x.iOrderByCol = i+1-pSort->nOBSat;
}
}
regOrig = 0;
assert( eDest==SRT_Set || eDest==SRT_Mem
|| eDest==SRT_Coroutine || eDest==SRT_Output );
}
nResultCol = sqlite3ExprCodeExprList(pParse,pEList,regResult,0,ecelFlags);
}
/* If the DISTINCT keyword was present on the SELECT statement
@ -875,7 +901,7 @@ static void selectInnerLoop(
** does not matter. But there might be a LIMIT clause, in which
** case the order does matter */
pushOntoSorter(
pParse, pSort, p, regResult, regResult, nResultCol, nPrefixReg);
pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
}else{
int r1 = sqlite3GetTempReg(pParse);
assert( sqlite3Strlen30(pDest->zAffSdst)==nResultCol );
@ -901,11 +927,12 @@ static void selectInnerLoop(
** memory cells and break out of the scan loop.
*/
case SRT_Mem: {
assert( nResultCol==pDest->nSdst );
if( pSort ){
assert( nResultCol<=pDest->nSdst );
pushOntoSorter(
pParse, pSort, p, regResult, regResult, nResultCol, nPrefixReg);
pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
}else{
assert( nResultCol==pDest->nSdst );
assert( regResult==iParm );
/* The LIMIT clause will jump out of the loop for us */
}
@ -918,7 +945,7 @@ static void selectInnerLoop(
testcase( eDest==SRT_Coroutine );
testcase( eDest==SRT_Output );
if( pSort ){
pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol,
pushOntoSorter(pParse, pSort, p, regResult, regOrig, nResultCol,
nPrefixReg);
}else if( eDest==SRT_Coroutine ){
sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm);
@ -1203,14 +1230,13 @@ static void generateSortTail(
int iParm = pDest->iSDParm;
int regRow;
int regRowid;
int iCol;
int nKey;
int iSortTab; /* Sorter cursor to read from */
int nSortData; /* Trailing values to read from sorter */
int i;
int bSeq; /* True if sorter record includes seq. no. */
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
struct ExprList_item *aOutEx = p->pEList->a;
#endif
assert( addrBreak<0 );
if( pSort->labelBkOut ){
@ -1248,8 +1274,14 @@ static void generateSortTail(
iSortTab = iTab;
bSeq = 1;
}
for(i=0; i<nSortData; i++){
sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i);
for(i=0, iCol=nKey+bSeq; i<nSortData; i++){
int iRead;
if( aOutEx[i].u.x.iOrderByCol ){
iRead = aOutEx[i].u.x.iOrderByCol-1;
}else{
iRead = iCol++;
}
sqlite3VdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow+i);
VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan));
}
switch( eDest ){

View File

@ -3706,6 +3706,7 @@ int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8);
#define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */
#define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */
#define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */
#define SQLITE_ECEL_OMITREF 0x08 /* Omit if ExprList.u.x.iOrderByCol */
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int);