1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-05 07:21:24 +03:00

Add an explicit representation of the output targetlist to Paths.

Up to now, there's been an assumption that all Paths for a given relation
compute the same output column set (targetlist).  However, there are good
reasons to remove that assumption.  For example, an indexscan on an
expression index might be able to return the value of an expensive function
"for free".  While we have the ability to generate such a plan today in
simple cases, we don't have a way to model that it's cheaper than a plan
that computes the function from scratch, nor a way to create such a plan
in join cases (where the function computation would normally happen at
the topmost join node).  Also, we need this so that we can have Paths
representing post-scan/join steps, where the targetlist may well change
from one step to the next.  Therefore, invent a "struct PathTarget"
representing the columns we expect a plan step to emit.  It's convenient
to include the output tuple width and tlist evaluation cost in this struct,
and there will likely be additional fields in future.

While Path nodes that actually do have custom outputs will need their own
PathTargets, it will still be true that most Paths for a given relation
will compute the same tlist.  To reduce the overhead added by this patch,
keep a "default PathTarget" in RelOptInfo, and allow Paths that compute
that column set to just point to their parent RelOptInfo's reltarget.
(In the patch as committed, actually every Path is like that, since we
do not yet have any cases of custom PathTargets.)

I took this opportunity to provide some more-honest costing of
PlaceHolderVar evaluation.  Up to now, the assumption that "scan/join
reltargetlists have cost zero" was applied not only to Vars, where it's
reasonable, but also PlaceHolderVars where it isn't.  Now, we add the eval
cost of a PlaceHolderVar's expression to the first plan level where it can
be computed, by including it in the PathTarget cost field and adding that
to the cost estimates for Paths.  This isn't perfect yet but it's much
better than before, and there is a way forward to improve it more.  This
costing change affects the join order chosen for a couple of the regression
tests, changing expected row ordering.
This commit is contained in:
Tom Lane
2016-02-18 20:01:49 -05:00
parent 3386f34cdc
commit 19a541143a
18 changed files with 337 additions and 154 deletions

View File

@ -919,19 +919,20 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
/*
* CE failed, so finish copying/modifying targetlist and join quals.
*
* Note: the resulting childrel->reltargetlist may contain arbitrary
* expressions, which otherwise would not occur in a reltargetlist.
* Note: the resulting childrel->reltarget.exprs may contain arbitrary
* expressions, which otherwise would not occur in a rel's targetlist.
* Code that might be looking at an appendrel child must cope with
* such. (Normally, a reltargetlist would only include Vars and
* PlaceHolderVars.)
* such. (Normally, a rel's targetlist would only include Vars and
* PlaceHolderVars.) XXX we do not bother to update the cost or width
* fields of childrel->reltarget; not clear if that would be useful.
*/
childrel->joininfo = (List *)
adjust_appendrel_attrs(root,
(Node *) rel->joininfo,
appinfo);
childrel->reltargetlist = (List *)
childrel->reltarget.exprs = (List *)
adjust_appendrel_attrs(root,
(Node *) rel->reltargetlist,
(Node *) rel->reltarget.exprs,
appinfo);
/*
@ -976,7 +977,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
Assert(childrel->rows > 0);
parent_rows += childrel->rows;
parent_size += childrel->width * childrel->rows;
parent_size += childrel->reltarget.width * childrel->rows;
/*
* Accumulate per-column estimates too. We need not do anything for
@ -984,10 +985,10 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
* Var, or we didn't record a width estimate for it, we have to fall
* back on a datatype-based estimate.
*
* By construction, child's reltargetlist is 1-to-1 with parent's.
* By construction, child's targetlist is 1-to-1 with parent's.
*/
forboth(parentvars, rel->reltargetlist,
childvars, childrel->reltargetlist)
forboth(parentvars, rel->reltarget.exprs,
childvars, childrel->reltarget.exprs)
{
Var *parentvar = (Var *) lfirst(parentvars);
Node *childvar = (Node *) lfirst(childvars);
@ -1022,7 +1023,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
Assert(parent_rows > 0);
rel->rows = parent_rows;
rel->width = rint(parent_size / parent_rows);
rel->reltarget.width = rint(parent_size / parent_rows);
for (i = 0; i < nattrs; i++)
rel->attr_widths[i] = rint(parent_attrsizes[i] / parent_rows);
@ -1495,7 +1496,7 @@ set_dummy_rel_pathlist(RelOptInfo *rel)
{
/* Set dummy size estimates --- we leave attr_widths[] as zeroes */
rel->rows = 0;
rel->width = 0;
rel->reltarget.width = 0;
/* Discard any pre-existing paths; no further need for them */
rel->pathlist = NIL;
@ -1728,11 +1729,11 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
ListCell *lc;
/*
* Is there a Var for it in reltargetlist? If not, the query did not
* reference the ordinality column, or at least not in any way that
* would be interesting for sorting.
* Is there a Var for it in rel's targetlist? If not, the query did
* not reference the ordinality column, or at least not in any way
* that would be interesting for sorting.
*/
foreach(lc, rel->reltargetlist)
foreach(lc, rel->reltarget.exprs)
{
Var *node = (Var *) lfirst(lc);
@ -2676,11 +2677,11 @@ remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel)
* query.
*
* Add all the attributes needed for joins or final output. Note: we must
* look at reltargetlist, not the attr_needed data, because attr_needed
* look at rel's targetlist, not the attr_needed data, because attr_needed
* isn't computed for inheritance child rels, cf set_append_rel_size().
* (XXX might be worth changing that sometime.)
*/
pull_varattnos((Node *) rel->reltargetlist, rel->relid, &attrs_used);
pull_varattnos((Node *) rel->reltarget.exprs, rel->relid, &attrs_used);
/* Add all the attributes used by un-pushed-down restriction clauses. */
foreach(lc, rel->baserestrictinfo)