Skip to content

Commit d2c555e

Browse files
committed
Teach nodeSort and nodeMaterial to optimize out unnecessary overhead
when the passed-down eflags indicate they can. Simon Riggs and Tom Lane
1 parent 2c0ef97 commit d2c555e

File tree

3 files changed

+80
-31
lines changed

3 files changed

+80
-31
lines changed

src/backend/executor/nodeMaterial.c

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.52 2006/02/28 04:10:27 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.53 2006/02/28 05:48:44 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -58,9 +58,9 @@ ExecMaterial(MaterialState *node)
5858
tuplestorestate = (Tuplestorestate *) node->tuplestorestate;
5959

6060
/*
61-
* If first time through, initialize the tuplestore.
61+
* If first time through, and we need a tuplestore, initialize it.
6262
*/
63-
if (tuplestorestate == NULL)
63+
if (tuplestorestate == NULL && node->randomAccess)
6464
{
6565
tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
6666

@@ -71,7 +71,8 @@ ExecMaterial(MaterialState *node)
7171
* If we are not at the end of the tuplestore, or are going backwards, try
7272
* to fetch a tuple from tuplestore.
7373
*/
74-
eof_tuplestore = tuplestore_ateof(tuplestorestate);
74+
eof_tuplestore = (tuplestorestate == NULL) ||
75+
tuplestore_ateof(tuplestorestate);
7576

7677
if (!forward && eof_tuplestore)
7778
{
@@ -135,7 +136,8 @@ ExecMaterial(MaterialState *node)
135136
* tuplestore is certainly in EOF state, its read position will move
136137
* forward over the added tuple. This is what we want.
137138
*/
138-
tuplestore_puttuple(tuplestorestate, (void *) heapTuple);
139+
if (tuplestorestate)
140+
tuplestore_puttuple(tuplestorestate, (void *) heapTuple);
139141
}
140142

141143
/*
@@ -165,8 +167,18 @@ ExecInitMaterial(Material *node, EState *estate, int eflags)
165167
matstate->ss.ps.plan = (Plan *) node;
166168
matstate->ss.ps.state = estate;
167169

168-
matstate->tuplestorestate = NULL;
170+
/*
171+
* We must have random access to the subplan output to do backward scan
172+
* or mark/restore. We also prefer to materialize the subplan output
173+
* if we might be called on to rewind and replay it many times.
174+
* However, if none of these cases apply, we can skip storing the data.
175+
*/
176+
matstate->randomAccess = (eflags & (EXEC_FLAG_REWIND |
177+
EXEC_FLAG_BACKWARD |
178+
EXEC_FLAG_MARK)) != 0;
179+
169180
matstate->eof_underlying = false;
181+
matstate->tuplestorestate = NULL;
170182

171183
/*
172184
* Miscellaneous initialization
@@ -249,6 +261,8 @@ ExecEndMaterial(MaterialState *node)
249261
void
250262
ExecMaterialMarkPos(MaterialState *node)
251263
{
264+
Assert(node->randomAccess);
265+
252266
/*
253267
* if we haven't materialized yet, just return.
254268
*/
@@ -267,6 +281,8 @@ ExecMaterialMarkPos(MaterialState *node)
267281
void
268282
ExecMaterialRestrPos(MaterialState *node)
269283
{
284+
Assert(node->randomAccess);
285+
270286
/*
271287
* if we haven't materialized yet, just return.
272288
*/
@@ -288,29 +304,44 @@ ExecMaterialRestrPos(MaterialState *node)
288304
void
289305
ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
290306
{
291-
/*
292-
* If we haven't materialized yet, just return. If outerplan' chgParam is
293-
* not NULL then it will be re-scanned by ExecProcNode, else - no reason
294-
* to re-scan it at all.
295-
*/
296-
if (!node->tuplestorestate)
297-
return;
298-
299307
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
300308

301-
/*
302-
* If subnode is to be rescanned then we forget previous stored results;
303-
* we have to re-read the subplan and re-store.
304-
*
305-
* Otherwise we can just rewind and rescan the stored output. The state of
306-
* the subnode does not change.
307-
*/
308-
if (((PlanState *) node)->lefttree->chgParam != NULL)
309+
if (node->randomAccess)
309310
{
310-
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
311-
node->tuplestorestate = NULL;
312-
node->eof_underlying = false;
311+
/*
312+
* If we haven't materialized yet, just return. If outerplan' chgParam
313+
* is not NULL then it will be re-scanned by ExecProcNode, else - no
314+
* reason to re-scan it at all.
315+
*/
316+
if (!node->tuplestorestate)
317+
return;
318+
319+
/*
320+
* If subnode is to be rescanned then we forget previous stored
321+
* results; we have to re-read the subplan and re-store.
322+
*
323+
* Otherwise we can just rewind and rescan the stored output. The
324+
* state of the subnode does not change.
325+
*/
326+
if (((PlanState *) node)->lefttree->chgParam != NULL)
327+
{
328+
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
329+
node->tuplestorestate = NULL;
330+
node->eof_underlying = false;
331+
}
332+
else
333+
tuplestore_rescan((Tuplestorestate *) node->tuplestorestate);
313334
}
314335
else
315-
tuplestore_rescan((Tuplestorestate *) node->tuplestorestate);
336+
{
337+
/* In this case we are just passing on the subquery's output */
338+
339+
/*
340+
* if chgParam of subnode is not null then plan will be re-scanned by
341+
* first ExecProcNode.
342+
*/
343+
if (((PlanState *) node)->lefttree->chgParam == NULL)
344+
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
345+
node->eof_underlying = false;
346+
}
316347
}

src/backend/executor/nodeSort.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/nodeSort.c,v 1.54 2006/02/28 04:10:27 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/nodeSort.c,v 1.55 2006/02/28 05:48:44 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -89,7 +89,7 @@ ExecSort(SortState *node)
8989
plannode->sortOperators,
9090
plannode->sortColIdx,
9191
work_mem,
92-
true /* randomAccess */ );
92+
node->randomAccess);
9393
node->tuplesortstate = (void *) tuplesortstate;
9494

9595
/*
@@ -164,6 +164,15 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
164164
sortstate->ss.ps.plan = (Plan *) node;
165165
sortstate->ss.ps.state = estate;
166166

167+
/*
168+
* We must have random access to the sort output to do backward scan
169+
* or mark/restore. We also prefer to materialize the sort output
170+
* if we might be called on to rewind and replay it many times.
171+
*/
172+
sortstate->randomAccess = (eflags & (EXEC_FLAG_REWIND |
173+
EXEC_FLAG_BACKWARD |
174+
EXEC_FLAG_MARK)) != 0;
175+
167176
sortstate->sort_Done = false;
168177
sortstate->tuplesortstate = NULL;
169178

@@ -308,11 +317,18 @@ ExecReScanSort(SortState *node, ExprContext *exprCtxt)
308317
*
309318
* Otherwise we can just rewind and rescan the sorted output.
310319
*/
311-
if (((PlanState *) node)->lefttree->chgParam != NULL)
320+
if (((PlanState *) node)->lefttree->chgParam != NULL ||
321+
!node->randomAccess)
312322
{
313323
node->sort_Done = false;
314324
tuplesort_end((Tuplesortstate *) node->tuplesortstate);
315325
node->tuplesortstate = NULL;
326+
/*
327+
* if chgParam of subnode is not null then plan will be re-scanned by
328+
* first ExecProcNode.
329+
*/
330+
if (((PlanState *) node)->lefttree->chgParam == NULL)
331+
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
316332
}
317333
else
318334
tuplesort_rescan((Tuplesortstate *) node->tuplesortstate);

src/include/nodes/execnodes.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.147 2005/12/28 01:30:01 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.148 2006/02/28 05:48:44 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -1185,8 +1185,9 @@ typedef struct HashJoinState
11851185
typedef struct MaterialState
11861186
{
11871187
ScanState ss; /* its first field is NodeTag */
1188-
void *tuplestorestate; /* private state of tuplestore.c */
1188+
bool randomAccess; /* need random access to subplan output? */
11891189
bool eof_underlying; /* reached end of underlying plan? */
1190+
void *tuplestorestate; /* private state of tuplestore.c */
11901191
} MaterialState;
11911192

11921193
/* ----------------
@@ -1196,6 +1197,7 @@ typedef struct MaterialState
11961197
typedef struct SortState
11971198
{
11981199
ScanState ss; /* its first field is NodeTag */
1200+
bool randomAccess; /* need random access to sort output? */
11991201
bool sort_Done; /* sort completed yet? */
12001202
void *tuplesortstate; /* private state of tuplesort.c */
12011203
} SortState;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy