mirror of
https://github.com/postgres/postgres.git
synced 2025-07-07 00:36:50 +03:00
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.
This commit is contained in:
@ -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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1038,6 +1038,23 @@ cost_sort(Path *path, PlannerInfo *root,
|
||||
path->total_cost = startup_cost + run_cost;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1600,6 +1600,30 @@ create_mergejoin_plan(PlannerInfo *root,
|
||||
else
|
||||
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
|
||||
|
Reference in New Issue
Block a user