mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +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:
@@ -476,7 +476,7 @@ build_path_tlist(PlannerInfo *root, Path *path)
|
||||
int resno = 1;
|
||||
ListCell *v;
|
||||
|
||||
foreach(v, rel->reltargetlist)
|
||||
foreach(v, rel->reltarget.exprs)
|
||||
{
|
||||
/* Do we really need to copy here? Not sure */
|
||||
Node *node = (Node *) copyObject(lfirst(v));
|
||||
@@ -875,9 +875,8 @@ create_result_plan(PlannerInfo *root, ResultPath *best_path)
|
||||
List *tlist;
|
||||
List *quals;
|
||||
|
||||
/* The tlist will be installed later, since we have no RelOptInfo */
|
||||
Assert(best_path->path.parent == NULL);
|
||||
tlist = NIL;
|
||||
/* This is a bit useless currently, because rel will have empty tlist */
|
||||
tlist = build_path_tlist(root, &best_path->path);
|
||||
|
||||
/* best_path->quals is just bare clauses */
|
||||
|
||||
@@ -2183,7 +2182,7 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
|
||||
/*
|
||||
* If rel is a base relation, detect whether any system columns are
|
||||
* requested from the rel. (If rel is a join relation, rel->relid will be
|
||||
* 0, but there can be no Var with relid 0 in the reltargetlist or the
|
||||
* 0, but there can be no Var with relid 0 in the rel's targetlist or the
|
||||
* restriction clauses, so we skip this in that case. Note that any such
|
||||
* columns in base relations that were joined are assumed to be contained
|
||||
* in fdw_scan_tlist.) This is a bit of a kluge and might go away someday,
|
||||
@@ -2198,10 +2197,10 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
|
||||
|
||||
/*
|
||||
* First, examine all the attributes needed for joins or final output.
|
||||
* Note: we must look at reltargetlist, not the attr_needed data,
|
||||
* Note: we must look at rel's targetlist, not the attr_needed data,
|
||||
* because attr_needed isn't computed for inheritance child rels.
|
||||
*/
|
||||
pull_varattnos((Node *) rel->reltargetlist, scan_relid, &attrs_used);
|
||||
pull_varattnos((Node *) rel->reltarget.exprs, scan_relid, &attrs_used);
|
||||
|
||||
/* Add all the attributes used by restriction clauses. */
|
||||
foreach(lc, rel->baserestrictinfo)
|
||||
@@ -3455,7 +3454,7 @@ copy_generic_path_info(Plan *dest, Path *src)
|
||||
dest->startup_cost = src->startup_cost;
|
||||
dest->total_cost = src->total_cost;
|
||||
dest->plan_rows = src->rows;
|
||||
dest->plan_width = src->parent->width;
|
||||
dest->plan_width = src->pathtarget->width;
|
||||
dest->parallel_aware = src->parallel_aware;
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user