aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-05-21 17:57:35 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-05-21 17:57:35 +0000
commit2415ad983174164ff30ce487c0e6b4b53321b83a (patch)
tree8f3bae7fd588a6cfa9bcaf33e6e5ea5f1cf89a4d /src/backend/optimizer
parent3963574d13383b4f377ab054e47e4af20cb75e7d (diff)
downloadpostgresql-2415ad983174164ff30ce487c0e6b4b53321b83a.tar.gz
postgresql-2415ad983174164ff30ce487c0e6b4b53321b83a.zip
Teach tuplestore.c to throw away data before the "mark" point when the caller
is using mark/restore but not rewind or backward-scan capability. Insert a materialize plan node between a mergejoin and its inner child if the inner child is a sort that is expected to spill to disk. The materialize shields the sort from the need to do mark/restore and thereby allows it to perform its final merge pass on-the-fly; while the materialize itself is normally cheap since it won't spill to disk unless the number of tuples with equal key values exceeds work_mem. Greg Stark, with some kibitzing from Tom Lane.
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/path/costsize.c19
-rw-r--r--src/backend/optimizer/plan/createplan.c26
2 files changed, 43 insertions, 2 deletions
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 82dfc77f065..55c7648b9e7 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -54,7 +54,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.182 2007/05/04 01:13:44 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.183 2007/05/21 17:57:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1039,6 +1039,23 @@ cost_sort(Path *path, PlannerInfo *root,
}
/*
+ * sort_exceeds_work_mem
+ * Given a finished Sort plan node, detect whether it is expected to
+ * spill to disk (ie, will need more than work_mem workspace)
+ *
+ * This assumes there will be no available LIMIT.
+ */
+bool
+sort_exceeds_work_mem(Sort *sort)
+{
+ double input_bytes = relation_byte_size(sort->plan.plan_rows,
+ sort->plan.plan_width);
+ long work_mem_bytes = work_mem * 1024L;
+
+ return (input_bytes > work_mem_bytes);
+}
+
+/*
* cost_material
* Determines and returns the cost of materializing a relation, including
* the cost of reading the input data.
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index be0162406bd..23099df6dc3 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.230 2007/05/04 01:13:44 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.231 2007/05/21 17:57:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1601,6 +1601,30 @@ create_mergejoin_plan(PlannerInfo *root,
innerpathkeys = best_path->jpath.innerjoinpath->pathkeys;
/*
+ * If inner plan is a sort that is expected to spill to disk, add a
+ * materialize node to shield it from the need to handle mark/restore.
+ * This will allow it to perform the last merge pass on-the-fly, while
+ * in most cases not requiring the materialize to spill to disk.
+ *
+ * XXX really, Sort oughta do this for itself, probably, to avoid the
+ * overhead of a separate plan node.
+ */
+ if (IsA(inner_plan, Sort) &&
+ sort_exceeds_work_mem((Sort *) inner_plan))
+ {
+ Plan *matplan = (Plan *) make_material(inner_plan);
+
+ /*
+ * We assume the materialize will not spill to disk, and therefore
+ * charge just cpu_tuple_cost per tuple.
+ */
+ copy_plan_costsize(matplan, inner_plan);
+ matplan->total_cost += cpu_tuple_cost * matplan->plan_rows;
+
+ inner_plan = matplan;
+ }
+
+ /*
* Compute the opfamily/strategy/nullsfirst arrays needed by the executor.
* The information is in the pathkeys for the two inputs, but we need to
* be careful about the possibility of mergeclauses sharing a pathkey