1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-02 09:02:37 +03:00

Tweak planner and executor to avoid doing ExecProject() in table scan

nodes where it's not really necessary.  In many cases where the scan node
is not the topmost plan node (eg, joins, aggregation), it's possible to
just return the table tuple directly instead of generating an intermediate
projection tuple.  In preliminary testing, this reduced the CPU time
needed for 'SELECT COUNT(*) FROM foo' by about 10%.
This commit is contained in:
Tom Lane
2003-02-03 15:07:08 +00:00
parent 0d3e36b668
commit 4cff59d8d5
12 changed files with 476 additions and 230 deletions

View File

@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.199 2003/01/23 05:10:37 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.200 2003/02/03 15:07:06 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -612,9 +612,11 @@ InitPlan(QueryDesc *queryDesc)
tupType = ExecGetTupType(planstate);
/*
* Initialize the junk filter if needed. SELECT and INSERT queries
* need a filter if there are any junk attrs in the tlist. UPDATE and
* DELETE always need one, since there's always a junk 'ctid'
* Initialize the junk filter if needed. SELECT and INSERT queries need a
* filter if there are any junk attrs in the tlist. INSERT and SELECT
* INTO also need a filter if the top plan node is a scan node that's not
* doing projection (else we'll be scribbling on the scan tuple!) UPDATE
* and DELETE always need a filter, since there's always a junk 'ctid'
* attribute present --- no need to look first.
*/
{
@ -635,6 +637,19 @@ InitPlan(QueryDesc *queryDesc)
break;
}
}
if (!junk_filter_needed &&
(operation == CMD_INSERT || do_select_into))
{
if (IsA(planstate, SeqScanState) ||
IsA(planstate, IndexScanState) ||
IsA(planstate, TidScanState) ||
IsA(planstate, SubqueryScanState) ||
IsA(planstate, FunctionScanState))
{
if (planstate->ps_ProjInfo == NULL)
junk_filter_needed = true;
}
}
break;
case CMD_UPDATE:
case CMD_DELETE:

View File

@ -12,19 +12,20 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.22 2002/12/05 15:50:32 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.23 2003/02/03 15:07:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <sys/file.h>
#include "executor/executor.h"
#include "miscadmin.h"
#include "utils/memutils.h"
static bool tlist_matches_tupdesc(List *tlist, Index varno, TupleDesc tupdesc);
/* ----------------------------------------------------------------
* ExecScan
*
@ -50,6 +51,7 @@ ExecScan(ScanState *node,
EState *estate;
ExprContext *econtext;
List *qual;
ProjectionInfo *projInfo;
ExprDoneCond isDone;
TupleTableSlot *resultSlot;
@ -59,6 +61,7 @@ ExecScan(ScanState *node,
estate = node->ps.state;
econtext = node->ps.ps_ExprContext;
qual = node->ps.qual;
projInfo = node->ps.ps_ProjInfo;
/*
* Check to see if we're still projecting out tuples from a previous
@ -67,7 +70,8 @@ ExecScan(ScanState *node,
*/
if (node->ps.ps_TupFromTlist)
{
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
Assert(projInfo); /* can't get here if not projecting */
resultSlot = ExecProject(projInfo, &isDone);
if (isDone == ExprMultipleResult)
return resultSlot;
/* Done with that source tuple... */
@ -101,10 +105,13 @@ ExecScan(ScanState *node,
*/
if (TupIsNull(slot))
{
return ExecStoreTuple(NULL,
node->ps.ps_ProjInfo->pi_slot,
InvalidBuffer,
true);
if (projInfo)
return ExecStoreTuple(NULL,
projInfo->pi_slot,
InvalidBuffer,
true);
else
return slot;
}
/*
@ -123,16 +130,27 @@ ExecScan(ScanState *node,
{
/*
* Found a satisfactory scan tuple.
*
* Form a projection tuple, store it in the result tuple slot and
* return it --- unless we find we can project no tuples from
* this scan tuple, in which case continue scan.
*/
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
if (isDone != ExprEndResult)
if (projInfo)
{
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
return resultSlot;
/*
* Form a projection tuple, store it in the result tuple slot
* and return it --- unless we find we can project no tuples
* from this scan tuple, in which case continue scan.
*/
resultSlot = ExecProject(projInfo, &isDone);
if (isDone != ExprEndResult)
{
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
return resultSlot;
}
}
else
{
/*
* Here, we aren't projecting, so just return scan tuple.
*/
return slot;
}
}
@ -142,3 +160,61 @@ ExecScan(ScanState *node,
ResetExprContext(econtext);
}
}
/*
* ExecAssignScanProjectionInfo
* Set up projection info for a scan node, if necessary.
*
* We can avoid a projection step if the requested tlist exactly matches
* the underlying tuple type. If so, we just set ps_ProjInfo to NULL.
* Note that this case occurs not only for simple "SELECT * FROM ...", but
* also in most cases where there are joins or other processing nodes above
* the scan node, because the planner will preferentially generate a matching
* tlist.
*
* ExecAssignScanType must have been called already.
*/
void
ExecAssignScanProjectionInfo(ScanState *node)
{
Scan *scan = (Scan *) node->ps.plan;
if (tlist_matches_tupdesc(scan->plan.targetlist,
scan->scanrelid,
node->ss_ScanTupleSlot->ttc_tupleDescriptor))
node->ps.ps_ProjInfo = NULL;
else
ExecAssignProjectionInfo(&node->ps);
}
static bool
tlist_matches_tupdesc(List *tlist, Index varno, TupleDesc tupdesc)
{
int numattrs = tupdesc->natts;
int attrno;
for (attrno = 1; attrno <= numattrs; attrno++)
{
Form_pg_attribute att_tup = tupdesc->attrs[attrno - 1];
Var *var;
if (tlist == NIL)
return false; /* tlist too short */
var = (Var *) ((TargetEntry *) lfirst(tlist))->expr;
if (!var || !IsA(var, Var))
return false; /* tlist item not a Var */
Assert(var->varno == varno);
if (var->varattno != attrno)
return false; /* out of order */
Assert(var->vartype == att_tup->atttypid);
Assert(var->vartypmod == att_tup->atttypmod);
Assert(var->varlevelsup == 0);
tlist = lnext(tlist);
}
if (tlist)
return false; /* tlist too long */
return true;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.77 2003/01/12 22:01:38 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.78 2003/02/03 15:07:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -582,12 +582,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
ExecInitScanTupleSlot(estate, &indexstate->ss);
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&indexstate->ss.ps);
ExecAssignProjectionInfo(&indexstate->ss.ps);
/*
* Initialize index-specific scan state
*/
@ -917,6 +911,12 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
indexstate->iss_RelationDescs = indexDescs;
indexstate->iss_ScanDescs = scanDescs;
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&indexstate->ss.ps);
ExecAssignScanProjectionInfo(&indexstate->ss);
/*
* all done.
*/

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.42 2003/01/12 22:01:38 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.43 2003/02/03 15:07:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -232,7 +232,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate)
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&scanstate->ps);
ExecAssignProjectionInfo(&scanstate->ps);
ExecAssignScanProjectionInfo(scanstate);
return scanstate;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.31 2003/01/12 22:01:38 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.32 2003/02/03 15:07:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -383,12 +383,6 @@ ExecInitTidScan(TidScan *node, EState *estate)
ExecInitResultTupleSlot(estate, &tidstate->ss.ps);
ExecInitScanTupleSlot(estate, &tidstate->ss);
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&tidstate->ss.ps);
ExecAssignProjectionInfo(&tidstate->ss.ps);
/*
* get the tid node information
*/
@ -438,6 +432,12 @@ ExecInitTidScan(TidScan *node, EState *estate)
*/
tidstate->ss.ps.chgParam = execParam;
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&tidstate->ss.ps);
ExecAssignScanProjectionInfo(&tidstate->ss);
/*
* all done.
*/