diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2020-09-27 12:51:28 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2020-09-27 12:51:28 -0400 |
commit | 41efb8340877e8ffd0023bb6b2ef22ffd1ca014d (patch) | |
tree | 74e248b1beb50cdbf1094684cbf4c00d146af5f2 /src/backend/executor | |
parent | 3c8819955023694feeaa456ee60853d0d6d0e60a (diff) | |
download | postgresql-41efb8340877e8ffd0023bb6b2ef22ffd1ca014d.tar.gz postgresql-41efb8340877e8ffd0023bb6b2ef22ffd1ca014d.zip |
Move resolution of AlternativeSubPlan choices to the planner.
When commit bd3daddaf introduced AlternativeSubPlans, I had some
ambitions towards allowing the choice of subplan to change during
execution. That has not happened, or even been thought about, in the
ensuing twelve years; so it seems like a failed experiment. So let's
rip that out and resolve the choice of subplan at the end of planning
(in setrefs.c) rather than during executor startup. This has a number
of positive benefits:
* Removal of a few hundred lines of executor code, since
AlternativeSubPlans need no longer be supported there.
* Removal of executor-startup overhead (particularly, initialization
of subplans that won't be used).
* Removal of incidental costs of having a larger plan tree, such as
tree-scanning and copying costs in the plancache; not to mention
setrefs.c's own costs of processing the discarded subplans.
* EXPLAIN no longer has to print a weird (and undocumented)
representation of an AlternativeSubPlan choice; it sees only the
subplan actually used. This should mean less confusion for users.
* Since setrefs.c knows which subexpression of a plan node it's
working on at any instant, it's possible to adjust the estimated
number of executions of the subplan based on that. For example,
we should usually estimate more executions of a qual expression
than a targetlist expression. The implementation used here is
pretty simplistic, because we don't want to expend a lot of cycles
on the issue; but it's better than ignoring the point entirely,
as the executor had to.
That last point might possibly result in shifting the choice
between hashed and non-hashed EXISTS subplans in a few cases,
but in general this patch isn't meant to change planner choices.
Since we're doing the resolution so late, it's really impossible
to change any plan choices outside the AlternativeSubPlan itself.
Patch by me; thanks to David Rowley for review.
Discussion: https://postgr.es/m/1992952.1592785225@sss.pgh.pa.us
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execExpr.c | 17 | ||||
-rw-r--r-- | src/backend/executor/execExprInterp.c | 23 | ||||
-rw-r--r-- | src/backend/executor/nodeSubplan.c | 80 |
3 files changed, 0 insertions, 120 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 236413f62aa..868f8b0858f 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -1104,23 +1104,6 @@ ExecInitExprRec(Expr *node, ExprState *state, break; } - case T_AlternativeSubPlan: - { - AlternativeSubPlan *asplan = (AlternativeSubPlan *) node; - AlternativeSubPlanState *asstate; - - if (!state->parent) - elog(ERROR, "AlternativeSubPlan found with no parent plan"); - - asstate = ExecInitAlternativeSubPlan(asplan, state->parent); - - scratch.opcode = EEOP_ALTERNATIVE_SUBPLAN; - scratch.d.alternative_subplan.asstate = asstate; - - ExprEvalPushStep(state, &scratch); - break; - } - case T_FieldSelect: { FieldSelect *fselect = (FieldSelect *) node; diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index b812bbaceef..26c2b496321 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -431,7 +431,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) &&CASE_EEOP_GROUPING_FUNC, &&CASE_EEOP_WINDOW_FUNC, &&CASE_EEOP_SUBPLAN, - &&CASE_EEOP_ALTERNATIVE_SUBPLAN, &&CASE_EEOP_AGG_STRICT_DESERIALIZE, &&CASE_EEOP_AGG_DESERIALIZE, &&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS, @@ -1536,14 +1535,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_NEXT(); } - EEO_CASE(EEOP_ALTERNATIVE_SUBPLAN) - { - /* too complex for an inline implementation */ - ExecEvalAlternativeSubPlan(state, op, econtext); - - EEO_NEXT(); - } - /* evaluate a strict aggregate deserialization function */ EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE) { @@ -3869,20 +3860,6 @@ ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext) } /* - * Hand off evaluation of an alternative subplan to nodeSubplan.c - */ -void -ExecEvalAlternativeSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext) -{ - AlternativeSubPlanState *asstate = op->d.alternative_subplan.asstate; - - /* could potentially be nested, so make sure there's enough stack */ - check_stack_depth(); - - *op->resvalue = ExecAlternativeSubPlan(asstate, econtext, op->resnull); -} - -/* * Evaluate a wholerow Var expression. * * Returns a Datum whose value is the value of a whole-row range variable diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 9a7962518ee..9a706df5f06 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -1303,83 +1303,3 @@ ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent) parent->chgParam = bms_add_member(parent->chgParam, paramid); } } - - -/* - * ExecInitAlternativeSubPlan - * - * Initialize for execution of one of a set of alternative subplans. - */ -AlternativeSubPlanState * -ExecInitAlternativeSubPlan(AlternativeSubPlan *asplan, PlanState *parent) -{ - AlternativeSubPlanState *asstate = makeNode(AlternativeSubPlanState); - double num_calls; - SubPlan *subplan1; - SubPlan *subplan2; - Cost cost1; - Cost cost2; - ListCell *lc; - - asstate->subplan = asplan; - - /* - * Initialize subplans. (Can we get away with only initializing the one - * we're going to use?) - */ - foreach(lc, asplan->subplans) - { - SubPlan *sp = lfirst_node(SubPlan, lc); - SubPlanState *sps = ExecInitSubPlan(sp, parent); - - asstate->subplans = lappend(asstate->subplans, sps); - parent->subPlan = lappend(parent->subPlan, sps); - } - - /* - * Select the one to be used. For this, we need an estimate of the number - * of executions of the subplan. We use the number of output rows - * expected from the parent plan node. This is a good estimate if we are - * in the parent's targetlist, and an underestimate (but probably not by - * more than a factor of 2) if we are in the qual. - */ - num_calls = parent->plan->plan_rows; - - /* - * The planner saved enough info so that we don't have to work very hard - * to estimate the total cost, given the number-of-calls estimate. - */ - Assert(list_length(asplan->subplans) == 2); - subplan1 = (SubPlan *) linitial(asplan->subplans); - subplan2 = (SubPlan *) lsecond(asplan->subplans); - - cost1 = subplan1->startup_cost + num_calls * subplan1->per_call_cost; - cost2 = subplan2->startup_cost + num_calls * subplan2->per_call_cost; - - if (cost1 < cost2) - asstate->active = 0; - else - asstate->active = 1; - - return asstate; -} - -/* - * ExecAlternativeSubPlan - * - * Execute one of a set of alternative subplans. - * - * Note: in future we might consider changing to different subplans on the - * fly, in case the original rowcount estimate turns out to be way off. - */ -Datum -ExecAlternativeSubPlan(AlternativeSubPlanState *node, - ExprContext *econtext, - bool *isNull) -{ - /* Just pass control to the active subplan */ - SubPlanState *activesp = list_nth_node(SubPlanState, - node->subplans, node->active); - - return ExecSubPlan(activesp, econtext, isNull); -} |