Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4cff59d

Browse files
committed
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%.
1 parent 0d3e36b commit 4cff59d

File tree

12 files changed

+462
-216
lines changed

12 files changed

+462
-216
lines changed

src/backend/executor/execMain.c

+19-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*
2727
*
2828
* IDENTIFICATION
29-
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.199 2003/01/23 05:10:37 tgl Exp $
29+
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.200 2003/02/03 15:07:06 tgl Exp $
3030
*
3131
*-------------------------------------------------------------------------
3232
*/
@@ -612,9 +612,11 @@ InitPlan(QueryDesc *queryDesc)
612612
tupType = ExecGetTupType(planstate);
613613

614614
/*
615-
* Initialize the junk filter if needed. SELECT and INSERT queries
616-
* need a filter if there are any junk attrs in the tlist. UPDATE and
617-
* DELETE always need one, since there's always a junk 'ctid'
615+
* Initialize the junk filter if needed. SELECT and INSERT queries need a
616+
* filter if there are any junk attrs in the tlist. INSERT and SELECT
617+
* INTO also need a filter if the top plan node is a scan node that's not
618+
* doing projection (else we'll be scribbling on the scan tuple!) UPDATE
619+
* and DELETE always need a filter, since there's always a junk 'ctid'
618620
* attribute present --- no need to look first.
619621
*/
620622
{
@@ -635,6 +637,19 @@ InitPlan(QueryDesc *queryDesc)
635637
break;
636638
}
637639
}
640+
if (!junk_filter_needed &&
641+
(operation == CMD_INSERT || do_select_into))
642+
{
643+
if (IsA(planstate, SeqScanState) ||
644+
IsA(planstate, IndexScanState) ||
645+
IsA(planstate, TidScanState) ||
646+
IsA(planstate, SubqueryScanState) ||
647+
IsA(planstate, FunctionScanState))
648+
{
649+
if (planstate->ps_ProjInfo == NULL)
650+
junk_filter_needed = true;
651+
}
652+
}
638653
break;
639654
case CMD_UPDATE:
640655
case CMD_DELETE:

src/backend/executor/execScan.c

+92-16
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,20 @@
1212
*
1313
*
1414
* IDENTIFICATION
15-
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.22 2002/12/05 15:50:32 tgl Exp $
15+
* $Header: /cvsroot/pgsql/src/backend/executor/execScan.c,v 1.23 2003/02/03 15:07:07 tgl Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
1919
#include "postgres.h"
2020

21-
#include <sys/file.h>
22-
2321
#include "executor/executor.h"
2422
#include "miscadmin.h"
2523
#include "utils/memutils.h"
2624

2725

26+
static bool tlist_matches_tupdesc(List *tlist, Index varno, TupleDesc tupdesc);
27+
28+
2829
/* ----------------------------------------------------------------
2930
* ExecScan
3031
*
@@ -50,6 +51,7 @@ ExecScan(ScanState *node,
5051
EState *estate;
5152
ExprContext *econtext;
5253
List *qual;
54+
ProjectionInfo *projInfo;
5355
ExprDoneCond isDone;
5456
TupleTableSlot *resultSlot;
5557

@@ -59,6 +61,7 @@ ExecScan(ScanState *node,
5961
estate = node->ps.state;
6062
econtext = node->ps.ps_ExprContext;
6163
qual = node->ps.qual;
64+
projInfo = node->ps.ps_ProjInfo;
6265

6366
/*
6467
* Check to see if we're still projecting out tuples from a previous
@@ -67,7 +70,8 @@ ExecScan(ScanState *node,
6770
*/
6871
if (node->ps.ps_TupFromTlist)
6972
{
70-
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
73+
Assert(projInfo); /* can't get here if not projecting */
74+
resultSlot = ExecProject(projInfo, &isDone);
7175
if (isDone == ExprMultipleResult)
7276
return resultSlot;
7377
/* Done with that source tuple... */
@@ -101,10 +105,13 @@ ExecScan(ScanState *node,
101105
*/
102106
if (TupIsNull(slot))
103107
{
104-
return ExecStoreTuple(NULL,
105-
node->ps.ps_ProjInfo->pi_slot,
106-
InvalidBuffer,
107-
true);
108+
if (projInfo)
109+
return ExecStoreTuple(NULL,
110+
projInfo->pi_slot,
111+
InvalidBuffer,
112+
true);
113+
else
114+
return slot;
108115
}
109116

110117
/*
@@ -123,16 +130,27 @@ ExecScan(ScanState *node,
123130
{
124131
/*
125132
* Found a satisfactory scan tuple.
126-
*
127-
* Form a projection tuple, store it in the result tuple slot and
128-
* return it --- unless we find we can project no tuples from
129-
* this scan tuple, in which case continue scan.
130133
*/
131-
resultSlot = ExecProject(node->ps.ps_ProjInfo, &isDone);
132-
if (isDone != ExprEndResult)
134+
if (projInfo)
133135
{
134-
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
135-
return resultSlot;
136+
/*
137+
* Form a projection tuple, store it in the result tuple slot
138+
* and return it --- unless we find we can project no tuples
139+
* from this scan tuple, in which case continue scan.
140+
*/
141+
resultSlot = ExecProject(projInfo, &isDone);
142+
if (isDone != ExprEndResult)
143+
{
144+
node->ps.ps_TupFromTlist = (isDone == ExprMultipleResult);
145+
return resultSlot;
146+
}
147+
}
148+
else
149+
{
150+
/*
151+
* Here, we aren't projecting, so just return scan tuple.
152+
*/
153+
return slot;
136154
}
137155
}
138156

@@ -142,3 +160,61 @@ ExecScan(ScanState *node,
142160
ResetExprContext(econtext);
143161
}
144162
}
163+
164+
/*
165+
* ExecAssignScanProjectionInfo
166+
* Set up projection info for a scan node, if necessary.
167+
*
168+
* We can avoid a projection step if the requested tlist exactly matches
169+
* the underlying tuple type. If so, we just set ps_ProjInfo to NULL.
170+
* Note that this case occurs not only for simple "SELECT * FROM ...", but
171+
* also in most cases where there are joins or other processing nodes above
172+
* the scan node, because the planner will preferentially generate a matching
173+
* tlist.
174+
*
175+
* ExecAssignScanType must have been called already.
176+
*/
177+
void
178+
ExecAssignScanProjectionInfo(ScanState *node)
179+
{
180+
Scan *scan = (Scan *) node->ps.plan;
181+
182+
if (tlist_matches_tupdesc(scan->plan.targetlist,
183+
scan->scanrelid,
184+
node->ss_ScanTupleSlot->ttc_tupleDescriptor))
185+
node->ps.ps_ProjInfo = NULL;
186+
else
187+
ExecAssignProjectionInfo(&node->ps);
188+
}
189+
190+
static bool
191+
tlist_matches_tupdesc(List *tlist, Index varno, TupleDesc tupdesc)
192+
{
193+
int numattrs = tupdesc->natts;
194+
int attrno;
195+
196+
for (attrno = 1; attrno <= numattrs; attrno++)
197+
{
198+
Form_pg_attribute att_tup = tupdesc->attrs[attrno - 1];
199+
Var *var;
200+
201+
if (tlist == NIL)
202+
return false; /* tlist too short */
203+
var = (Var *) ((TargetEntry *) lfirst(tlist))->expr;
204+
if (!var || !IsA(var, Var))
205+
return false; /* tlist item not a Var */
206+
Assert(var->varno == varno);
207+
if (var->varattno != attrno)
208+
return false; /* out of order */
209+
Assert(var->vartype == att_tup->atttypid);
210+
Assert(var->vartypmod == att_tup->atttypmod);
211+
Assert(var->varlevelsup == 0);
212+
213+
tlist = lnext(tlist);
214+
}
215+
216+
if (tlist)
217+
return false; /* tlist too long */
218+
219+
return true;
220+
}

src/backend/executor/nodeIndexscan.c

+7-7
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.77 2003/01/12 22:01:38 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.78 2003/02/03 15:07:07 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -582,12 +582,6 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
582582
ExecInitResultTupleSlot(estate, &indexstate->ss.ps);
583583
ExecInitScanTupleSlot(estate, &indexstate->ss);
584584

585-
/*
586-
* Initialize result tuple type and projection info.
587-
*/
588-
ExecAssignResultTypeFromTL(&indexstate->ss.ps);
589-
ExecAssignProjectionInfo(&indexstate->ss.ps);
590-
591585
/*
592586
* Initialize index-specific scan state
593587
*/
@@ -917,6 +911,12 @@ ExecInitIndexScan(IndexScan *node, EState *estate)
917911
indexstate->iss_RelationDescs = indexDescs;
918912
indexstate->iss_ScanDescs = scanDescs;
919913

914+
/*
915+
* Initialize result tuple type and projection info.
916+
*/
917+
ExecAssignResultTypeFromTL(&indexstate->ss.ps);
918+
ExecAssignScanProjectionInfo(&indexstate->ss);
919+
920920
/*
921921
* all done.
922922
*/

src/backend/executor/nodeSeqscan.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.42 2003/01/12 22:01:38 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.43 2003/02/03 15:07:07 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -232,7 +232,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate)
232232
* Initialize result tuple type and projection info.
233233
*/
234234
ExecAssignResultTypeFromTL(&scanstate->ps);
235-
ExecAssignProjectionInfo(&scanstate->ps);
235+
ExecAssignScanProjectionInfo(scanstate);
236236

237237
return scanstate;
238238
}

src/backend/executor/nodeTidscan.c

+7-7
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.31 2003/01/12 22:01:38 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.32 2003/02/03 15:07:07 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -383,12 +383,6 @@ ExecInitTidScan(TidScan *node, EState *estate)
383383
ExecInitResultTupleSlot(estate, &tidstate->ss.ps);
384384
ExecInitScanTupleSlot(estate, &tidstate->ss);
385385

386-
/*
387-
* Initialize result tuple type and projection info.
388-
*/
389-
ExecAssignResultTypeFromTL(&tidstate->ss.ps);
390-
ExecAssignProjectionInfo(&tidstate->ss.ps);
391-
392386
/*
393387
* get the tid node information
394388
*/
@@ -438,6 +432,12 @@ ExecInitTidScan(TidScan *node, EState *estate)
438432
*/
439433
tidstate->ss.ps.chgParam = execParam;
440434

435+
/*
436+
* Initialize result tuple type and projection info.
437+
*/
438+
ExecAssignResultTypeFromTL(&tidstate->ss.ps);
439+
ExecAssignScanProjectionInfo(&tidstate->ss);
440+
441441
/*
442442
* all done.
443443
*/

0 commit comments

Comments
 (0)