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:
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user