mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-11 01:42:22 +03:00
Do not compute result columns of subqueries that are never used. Make those
columns NULL instead. This optimization potentially resolves the enhancement request described by [/tktview/baa5bb76c35a124c|ticket baa5bb76c35a124c]. FossilOrigin-Name: 5dec3cc0225296a043d17f73126d477d90a604f82b3180628176d8f950adbce8
This commit is contained in:
65
src/select.c
65
src/select.c
@@ -5235,6 +5235,57 @@ static int pushDownWhereTerms(
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
|
||||
|
||||
/*
|
||||
** Check to see if a subquery contains result-set columns that are
|
||||
** never used. If it does, change the value of those result-set columns
|
||||
** to NULL so that they do not cause unnecessary work to compute.
|
||||
**
|
||||
** Return the number of column that were changed to NULL.
|
||||
*/
|
||||
static int disableUnusedSubqueryResultColumns(SrcItem *pItem){
|
||||
int nCol;
|
||||
Select *pSub; /* The subquery to be simplified */
|
||||
Select *pX; /* For looping over compound elements of pSub */
|
||||
Table *pTab; /* The table that describes the subquery */
|
||||
int j; /* Column number */
|
||||
int nChng = 0; /* Number of columns converted to NULL */
|
||||
|
||||
assert( pItem!=0 );
|
||||
assert( pItem->pTab!=0 );
|
||||
pTab = pItem->pTab;
|
||||
if( pTab->tabFlags & TF_Ephemeral ) return 0;
|
||||
assert( pItem->pSelect!=0 );
|
||||
pSub = pItem->pSelect;
|
||||
assert( pSub->pEList->nExpr==pTab->nCol );
|
||||
for(pX=pSub; pX; pX=pX->pPrior){
|
||||
if( pX->pPrior && pX->op!=TK_ALL ){
|
||||
/* This optimization does not work for compound subqueries that
|
||||
** use UNION, INTERSECT, or EXCEPT. Only UNION ALL is allowed. */
|
||||
return 0;
|
||||
}
|
||||
if( pX->pWin ){
|
||||
/* This optimization does not work for subqueries that use window
|
||||
** functions. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
nCol = pTab->nCol;
|
||||
for(j=0; j<nCol; j++){
|
||||
Select *pX;
|
||||
if( (MASKBIT(j) & pItem->colUsed)!=0 ) continue;
|
||||
if( MASKBIT(j)==0 ) break;
|
||||
for(pX=pSub; pX; pX=pX->pPrior) {
|
||||
Expr *pY = pX->pEList->a[j].pExpr;
|
||||
if( pY->op==TK_NULL ) continue;
|
||||
pY->op = TK_NULL;
|
||||
pX->selFlags |= SF_PushDown;
|
||||
nChng++;
|
||||
}
|
||||
}
|
||||
return nChng;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The pFunc is the only aggregate function in the query. Check to see
|
||||
** if the query is a candidate for the min/max optimization.
|
||||
@@ -7333,6 +7384,20 @@ int sqlite3Select(
|
||||
TREETRACE(0x4000,pParse,p,("Push-down not possible\n"));
|
||||
}
|
||||
|
||||
/* Convert unused result columns of the subquery into simple NULL
|
||||
** expressions, to avoid unneeded searching and computation.
|
||||
*/
|
||||
if( disableUnusedSubqueryResultColumns(pItem) ){
|
||||
#if TREETRACE_ENABLED
|
||||
if( sqlite3TreeTrace & 0x4000 ){
|
||||
TREETRACE(0x4000,pParse,p,
|
||||
("Change unused result columns to NULL for subquery %d:\n",
|
||||
pSub->selId));
|
||||
sqlite3TreeViewSelect(0, p, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
zSavedAuthContext = pParse->zAuthContext;
|
||||
pParse->zAuthContext = pItem->zName;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user