aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/setrefs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/setrefs.c')
-rw-r--r--src/backend/optimizer/plan/setrefs.c71
1 files changed, 47 insertions, 24 deletions
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index e50624c465e..3d23a2e5ac7 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -249,6 +249,7 @@ static List *set_returning_clause_references(PlannerInfo *root,
Plan *
set_plan_references(PlannerInfo *root, Plan *plan)
{
+ Plan *result;
PlannerGlobal *glob = root->glob;
int rtoffset = list_length(glob->finalrtable);
ListCell *lc;
@@ -301,8 +302,44 @@ set_plan_references(PlannerInfo *root, Plan *plan)
glob->appendRelations = lappend(glob->appendRelations, appinfo);
}
+ /* If needed, create workspace for processing AlternativeSubPlans */
+ if (root->hasAlternativeSubPlans)
+ {
+ root->isAltSubplan = (bool *)
+ palloc0(list_length(glob->subplans) * sizeof(bool));
+ root->isUsedSubplan = (bool *)
+ palloc0(list_length(glob->subplans) * sizeof(bool));
+ }
+
/* Now fix the Plan tree */
- return set_plan_refs(root, plan, rtoffset);
+ result = set_plan_refs(root, plan, rtoffset);
+
+ /*
+ * If we have AlternativeSubPlans, it is likely that we now have some
+ * unreferenced subplans in glob->subplans. To avoid expending cycles on
+ * those subplans later, get rid of them by setting those list entries to
+ * NULL. (Note: we can't do this immediately upon processing an
+ * AlternativeSubPlan, because there may be multiple copies of the
+ * AlternativeSubPlan, and they can get resolved differently.)
+ */
+ if (root->hasAlternativeSubPlans)
+ {
+ foreach(lc, glob->subplans)
+ {
+ int ndx = foreach_current_index(lc);
+
+ /*
+ * If it was used by some AlternativeSubPlan in this query level,
+ * but wasn't selected as best by any AlternativeSubPlan, then we
+ * don't need it. Do not touch subplans that aren't parts of
+ * AlternativeSubPlans.
+ */
+ if (root->isAltSubplan[ndx] && !root->isUsedSubplan[ndx])
+ lfirst(lc) = NULL;
+ }
+ }
+
+ return result;
}
/*
@@ -1765,8 +1802,7 @@ fix_param_node(PlannerInfo *root, Param *p)
* Note: caller must still recurse into the result!
*
* We don't make any attempt to fix up cost estimates in the parent plan
- * node or higher-level nodes. However, we do remove the rejected subplan(s)
- * from root->glob->subplans, to minimize cycles expended on them later.
+ * node or higher-level nodes.
*/
static Node *
fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan,
@@ -1778,9 +1814,8 @@ fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan,
/*
* Compute the estimated cost of each subplan assuming num_exec
- * executions, and keep the cheapest one. Replace discarded subplans with
- * NULL pointers in the global subplans list. In event of exact equality
- * of estimates, we prefer the later plan; this is a bit arbitrary, but in
+ * executions, and keep the cheapest one. In event of exact equality of
+ * estimates, we prefer the later plan; this is a bit arbitrary, but in
* current usage it biases us to break ties against fast-start subplans.
*/
Assert(asplan->subplans != NIL);
@@ -1791,31 +1826,19 @@ fix_alternative_subplan(PlannerInfo *root, AlternativeSubPlan *asplan,
Cost curcost;
curcost = curplan->startup_cost + num_exec * curplan->per_call_cost;
- if (bestplan == NULL)
- {
- bestplan = curplan;
- bestcost = curcost;
- }
- else if (curcost <= bestcost)
+ if (bestplan == NULL || curcost <= bestcost)
{
- /* drop old bestplan */
- ListCell *lc2 = list_nth_cell(root->glob->subplans,
- bestplan->plan_id - 1);
-
- lfirst(lc2) = NULL;
bestplan = curplan;
bestcost = curcost;
}
- else
- {
- /* drop curplan */
- ListCell *lc2 = list_nth_cell(root->glob->subplans,
- curplan->plan_id - 1);
- lfirst(lc2) = NULL;
- }
+ /* Also mark all subplans that are in AlternativeSubPlans */
+ root->isAltSubplan[curplan->plan_id - 1] = true;
}
+ /* Mark the subplan we selected */
+ root->isUsedSubplan[bestplan->plan_id - 1] = true;
+
return (Node *) bestplan;
}