1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Be more realistic about plans involving Materialize nodes: take their

cost into account while planning.
This commit is contained in:
Tom Lane
2002-11-30 05:21:03 +00:00
parent 829cedc8cf
commit 935969415a
19 changed files with 320 additions and 160 deletions

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.125 2002/11/30 00:08:17 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.126 2002/11/30 05:21:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -35,6 +35,7 @@ static Scan *create_scan_plan(Query *root, Path *best_path);
static Join *create_join_plan(Query *root, JoinPath *best_path);
static Append *create_append_plan(Query *root, AppendPath *best_path);
static Result *create_result_plan(Query *root, ResultPath *best_path);
static Material *create_material_plan(Query *root, MaterialPath *best_path);
static SeqScan *create_seqscan_plan(Path *best_path, List *tlist,
List *scan_clauses);
static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path,
@ -141,6 +142,10 @@ create_plan(Query *root, Path *best_path)
plan = (Plan *) create_result_plan(root,
(ResultPath *) best_path);
break;
case T_Material:
plan = (Plan *) create_material_plan(root,
(MaterialPath *) best_path);
break;
default:
elog(ERROR, "create_plan: unknown pathtype %d",
best_path->pathtype);
@ -383,6 +388,28 @@ create_result_plan(Query *root, ResultPath *best_path)
return plan;
}
/*
* create_material_plan
* Create a Material plan for 'best_path' and (recursively) plans
* for its subpaths.
*
* Returns a Plan node.
*/
static Material *
create_material_plan(Query *root, MaterialPath *best_path)
{
Material *plan;
Plan *subplan;
subplan = create_plan(root, best_path->subpath);
plan = make_material(best_path->path.parent->targetlist, subplan);
copy_path_costsize(&plan->plan, (Path *) best_path);
return plan;
}
/*****************************************************************************
*
@ -739,18 +766,6 @@ create_nestloop_plan(Query *root,
inner_tlist,
innerscan->scan.scanrelid);
}
else if (IsA_Join(inner_plan))
{
/*
* Materialize the inner join for speed reasons.
*
* XXX It is probably *not* always fastest to materialize an inner
* join --- how can we estimate whether this is a good thing to
* do?
*/
inner_plan = (Plan *) make_material(inner_tlist,
inner_plan);
}
/*
* Set quals to contain INNER/OUTER var references.
@ -842,44 +857,6 @@ create_mergejoin_plan(Query *root,
inner_plan,
best_path->innersortkeys);
/*
* The executor requires the inner side of a mergejoin to support
* "mark" and "restore" operations. Not all plan types do, so we must
* be careful not to generate an invalid plan. If necessary, an
* invalid inner plan can be handled by inserting a Materialize node.
*
* Since the inner side must be ordered, and only Sorts and IndexScans
* can create order to begin with, you might think there's no problem
* --- but you'd be wrong. Nestloop and merge joins can *preserve*
* the order of their inputs, so they can be selected as the input of
* a mergejoin, and that won't work in the present executor.
*
* Doing this here is a bit of a kluge since the cost of the Materialize
* wasn't taken into account in our earlier decisions. But
* Materialize is hard to estimate a cost for, and the above
* consideration shows that this is a rare case anyway, so this seems
* an acceptable way to proceed.
*
* This check must agree with ExecMarkPos/ExecRestrPos in
* executor/execAmi.c!
*/
switch (nodeTag(inner_plan))
{
case T_SeqScan:
case T_IndexScan:
case T_FunctionScan:
case T_Material:
case T_Sort:
/* OK, these inner plans support mark/restore */
break;
default:
/* Ooops, need to materialize the inner plan */
inner_plan = (Plan *) make_material(inner_tlist,
inner_plan);
break;
}
/*
* Now we can build the mergejoin node.
*/
@ -1668,15 +1645,7 @@ make_material(List *tlist, Plan *lefttree)
Material *node = makeNode(Material);
Plan *plan = &node->plan;
copy_plan_costsize(plan, lefttree);
/*
* For plausibility, make startup & total costs equal total cost of
* input plan; this only affects EXPLAIN display not decisions.
*
* XXX shouldn't we charge some additional cost for materialization?
*/
plan->startup_cost = plan->total_cost;
/* cost should be inserted by caller */
plan->state = (EState *) NULL;
plan->targetlist = tlist;
plan->qual = NIL;