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:
parent
2c0ef9777c
commit
d2c555ee53
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue