Teach nodeSort and nodeMaterial to optimize out unnecessary overhead

when the passed-down eflags indicate they can.
Simon Riggs and Tom Lane
This commit is contained in:
Tom Lane 2006-02-28 05:48:44 +00:00
parent 2c0ef9777c
commit d2c555ee53
3 changed files with 80 additions and 31 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.52 2006/02/28 04:10:27 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/nodeMaterial.c,v 1.53 2006/02/28 05:48:44 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -58,9 +58,9 @@ ExecMaterial(MaterialState *node)
tuplestorestate = (Tuplestorestate *) node->tuplestorestate; tuplestorestate = (Tuplestorestate *) node->tuplestorestate;
/* /*
* If first time through, initialize the tuplestore. * If first time through, and we need a tuplestore, initialize it.
*/ */
if (tuplestorestate == NULL) if (tuplestorestate == NULL && node->randomAccess)
{ {
tuplestorestate = tuplestore_begin_heap(true, false, work_mem); tuplestorestate = tuplestore_begin_heap(true, false, work_mem);
@ -71,7 +71,8 @@ ExecMaterial(MaterialState *node)
* If we are not at the end of the tuplestore, or are going backwards, try * If we are not at the end of the tuplestore, or are going backwards, try
* to fetch a tuple from tuplestore. * to fetch a tuple from tuplestore.
*/ */
eof_tuplestore = tuplestore_ateof(tuplestorestate); eof_tuplestore = (tuplestorestate == NULL) ||
tuplestore_ateof(tuplestorestate);
if (!forward && eof_tuplestore) if (!forward && eof_tuplestore)
{ {
@ -135,7 +136,8 @@ ExecMaterial(MaterialState *node)
* tuplestore is certainly in EOF state, its read position will move * tuplestore is certainly in EOF state, its read position will move
* forward over the added tuple. This is what we want. * forward over the added tuple. This is what we want.
*/ */
tuplestore_puttuple(tuplestorestate, (void *) heapTuple); if (tuplestorestate)
tuplestore_puttuple(tuplestorestate, (void *) heapTuple);
} }
/* /*
@ -165,8 +167,18 @@ ExecInitMaterial(Material *node, EState *estate, int eflags)
matstate->ss.ps.plan = (Plan *) node; matstate->ss.ps.plan = (Plan *) node;
matstate->ss.ps.state = estate; matstate->ss.ps.state = estate;
matstate->tuplestorestate = NULL; /*
* We must have random access to the subplan output to do backward scan
* or mark/restore. We also prefer to materialize the subplan output
* if we might be called on to rewind and replay it many times.
* However, if none of these cases apply, we can skip storing the data.
*/
matstate->randomAccess = (eflags & (EXEC_FLAG_REWIND |
EXEC_FLAG_BACKWARD |
EXEC_FLAG_MARK)) != 0;
matstate->eof_underlying = false; matstate->eof_underlying = false;
matstate->tuplestorestate = NULL;
/* /*
* Miscellaneous initialization * Miscellaneous initialization
@ -249,6 +261,8 @@ ExecEndMaterial(MaterialState *node)
void void
ExecMaterialMarkPos(MaterialState *node) ExecMaterialMarkPos(MaterialState *node)
{ {
Assert(node->randomAccess);
/* /*
* if we haven't materialized yet, just return. * if we haven't materialized yet, just return.
*/ */
@ -267,6 +281,8 @@ ExecMaterialMarkPos(MaterialState *node)
void void
ExecMaterialRestrPos(MaterialState *node) ExecMaterialRestrPos(MaterialState *node)
{ {
Assert(node->randomAccess);
/* /*
* if we haven't materialized yet, just return. * if we haven't materialized yet, just return.
*/ */
@ -288,29 +304,44 @@ ExecMaterialRestrPos(MaterialState *node)
void void
ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt) ExecMaterialReScan(MaterialState *node, ExprContext *exprCtxt)
{ {
/*
* If we haven't materialized yet, just return. If outerplan' chgParam is
* not NULL then it will be re-scanned by ExecProcNode, else - no reason
* to re-scan it at all.
*/
if (!node->tuplestorestate)
return;
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot); ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
/* if (node->randomAccess)
* If subnode is to be rescanned then we forget previous stored results;
* we have to re-read the subplan and re-store.
*
* Otherwise we can just rewind and rescan the stored output. The state of
* the subnode does not change.
*/
if (((PlanState *) node)->lefttree->chgParam != NULL)
{ {
tuplestore_end((Tuplestorestate *) node->tuplestorestate); /*
node->tuplestorestate = NULL; * If we haven't materialized yet, just return. If outerplan' chgParam
node->eof_underlying = false; * is not NULL then it will be re-scanned by ExecProcNode, else - no
* reason to re-scan it at all.
*/
if (!node->tuplestorestate)
return;
/*
* If subnode is to be rescanned then we forget previous stored
* results; we have to re-read the subplan and re-store.
*
* Otherwise we can just rewind and rescan the stored output. The
* state of the subnode does not change.
*/
if (((PlanState *) node)->lefttree->chgParam != NULL)
{
tuplestore_end((Tuplestorestate *) node->tuplestorestate);
node->tuplestorestate = NULL;
node->eof_underlying = false;
}
else
tuplestore_rescan((Tuplestorestate *) node->tuplestorestate);
} }
else else
tuplestore_rescan((Tuplestorestate *) node->tuplestorestate); {
/* In this case we are just passing on the subquery's output */
/*
* if chgParam of subnode is not null then plan will be re-scanned by
* first ExecProcNode.
*/
if (((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
node->eof_underlying = false;
}
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeSort.c,v 1.54 2006/02/28 04:10:27 tgl Exp $ * $PostgreSQL: pgsql/src/backend/executor/nodeSort.c,v 1.55 2006/02/28 05:48:44 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -89,7 +89,7 @@ ExecSort(SortState *node)
plannode->sortOperators, plannode->sortOperators,
plannode->sortColIdx, plannode->sortColIdx,
work_mem, work_mem,
true /* randomAccess */ ); node->randomAccess);
node->tuplesortstate = (void *) tuplesortstate; node->tuplesortstate = (void *) tuplesortstate;
/* /*
@ -164,6 +164,15 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
sortstate->ss.ps.plan = (Plan *) node; sortstate->ss.ps.plan = (Plan *) node;
sortstate->ss.ps.state = estate; sortstate->ss.ps.state = estate;
/*
* We must have random access to the sort output to do backward scan
* or mark/restore. We also prefer to materialize the sort output
* if we might be called on to rewind and replay it many times.
*/
sortstate->randomAccess = (eflags & (EXEC_FLAG_REWIND |
EXEC_FLAG_BACKWARD |
EXEC_FLAG_MARK)) != 0;
sortstate->sort_Done = false; sortstate->sort_Done = false;
sortstate->tuplesortstate = NULL; sortstate->tuplesortstate = NULL;
@ -308,11 +317,18 @@ ExecReScanSort(SortState *node, ExprContext *exprCtxt)
* *
* Otherwise we can just rewind and rescan the sorted output. * Otherwise we can just rewind and rescan the sorted output.
*/ */
if (((PlanState *) node)->lefttree->chgParam != NULL) if (((PlanState *) node)->lefttree->chgParam != NULL ||
!node->randomAccess)
{ {
node->sort_Done = false; node->sort_Done = false;
tuplesort_end((Tuplesortstate *) node->tuplesortstate); tuplesort_end((Tuplesortstate *) node->tuplesortstate);
node->tuplesortstate = NULL; node->tuplesortstate = NULL;
/*
* if chgParam of subnode is not null then plan will be re-scanned by
* first ExecProcNode.
*/
if (((PlanState *) node)->lefttree->chgParam == NULL)
ExecReScan(((PlanState *) node)->lefttree, exprCtxt);
} }
else else
tuplesort_rescan((Tuplesortstate *) node->tuplesortstate); tuplesort_rescan((Tuplesortstate *) node->tuplesortstate);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.147 2005/12/28 01:30:01 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.148 2006/02/28 05:48:44 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1185,8 +1185,9 @@ typedef struct HashJoinState
typedef struct MaterialState typedef struct MaterialState
{ {
ScanState ss; /* its first field is NodeTag */ ScanState ss; /* its first field is NodeTag */
void *tuplestorestate; /* private state of tuplestore.c */ bool randomAccess; /* need random access to subplan output? */
bool eof_underlying; /* reached end of underlying plan? */ bool eof_underlying; /* reached end of underlying plan? */
void *tuplestorestate; /* private state of tuplestore.c */
} MaterialState; } MaterialState;
/* ---------------- /* ----------------
@ -1196,6 +1197,7 @@ typedef struct MaterialState
typedef struct SortState typedef struct SortState
{ {
ScanState ss; /* its first field is NodeTag */ ScanState ss; /* its first field is NodeTag */
bool randomAccess; /* need random access to sort output? */
bool sort_Done; /* sort completed yet? */ bool sort_Done; /* sort completed yet? */
void *tuplesortstate; /* private state of tuplesort.c */ void *tuplesortstate; /* private state of tuplesort.c */
} SortState; } SortState;