Teach nodeSort and nodeMaterial to optimize out unnecessary overhead
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 28 Feb 2006 05:48:44 +0000 (05:48 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 28 Feb 2006 05:48:44 +0000 (05:48 +0000)
when the passed-down eflags indicate they can.
Simon Riggs and Tom Lane

src/backend/executor/nodeMaterial.c
src/backend/executor/nodeSort.c
src/include/nodes/execnodes.h

index 641fe3afc2d264ab8d3e47322cacd5b3d0588a93..34e1b2538fab778f270b61950639b565ee13cb64 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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;
 
        /*
-        * 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);
 
@@ -71,7 +71,8 @@ ExecMaterial(MaterialState *node)
         * If we are not at the end of the tuplestore, or are going backwards, try
         * to fetch a tuple from tuplestore.
         */
-       eof_tuplestore = tuplestore_ateof(tuplestorestate);
+       eof_tuplestore = (tuplestorestate == NULL) ||
+               tuplestore_ateof(tuplestorestate);
 
        if (!forward && eof_tuplestore)
        {
@@ -135,7 +136,8 @@ ExecMaterial(MaterialState *node)
                 * tuplestore is certainly in EOF state, its read position will move
                 * 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.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->tuplestorestate = NULL;
 
        /*
         * Miscellaneous initialization
@@ -249,6 +261,8 @@ ExecEndMaterial(MaterialState *node)
 void
 ExecMaterialMarkPos(MaterialState *node)
 {
+       Assert(node->randomAccess);
+
        /*
         * if we haven't materialized yet, just return.
         */
@@ -267,6 +281,8 @@ ExecMaterialMarkPos(MaterialState *node)
 void
 ExecMaterialRestrPos(MaterialState *node)
 {
+       Assert(node->randomAccess);
+
        /*
         * if we haven't materialized yet, just return.
         */
@@ -288,29 +304,44 @@ ExecMaterialRestrPos(MaterialState *node)
 void
 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);
 
-       /*
-        * 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)
+       if (node->randomAccess)
        {
-               tuplestore_end((Tuplestorestate *) node->tuplestorestate);
-               node->tuplestorestate = NULL;
-               node->eof_underlying = false;
+               /*
+                * 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;
+
+               /*
+                * 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
-               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;
+       }
 }
index 367adbfbe20c2d073f5d8b066b01456a69c0d000..f799c78218a6c034576cd9312e13c06b84333185 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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->sortColIdx,
                                                                                          work_mem,
-                                                                                         true /* randomAccess */ );
+                                                                                         node->randomAccess);
                node->tuplesortstate = (void *) tuplesortstate;
 
                /*
@@ -164,6 +164,15 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
        sortstate->ss.ps.plan = (Plan *) node;
        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->tuplesortstate = NULL;
 
@@ -308,11 +317,18 @@ ExecReScanSort(SortState *node, ExprContext *exprCtxt)
         *
         * 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;
                tuplesort_end((Tuplesortstate *) node->tuplesortstate);
                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
                tuplesort_rescan((Tuplesortstate *) node->tuplesortstate);
index d07dc57297c3f7137602a5bc0f5342688bc260b9..f277672a1c471c9241e8d89a02cd265a303b184c 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * 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
 {
        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? */
+       void       *tuplestorestate;    /* private state of tuplestore.c */
 } MaterialState;
 
 /* ----------------
@@ -1196,6 +1197,7 @@ typedef struct MaterialState
 typedef struct SortState
 {
        ScanState       ss;                             /* its first field is NodeTag */
+       bool            randomAccess;   /* need random access to sort output? */
        bool            sort_Done;              /* sort completed yet? */
        void       *tuplesortstate; /* private state of tuplesort.c */
 } SortState;