Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 41efb83

Browse files
committed
Move resolution of AlternativeSubPlan choices to the planner.
When commit bd3dadd 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
1 parent 3c88199 commit 41efb83

20 files changed

+412
-295
lines changed

src/backend/executor/execExpr.c

-17
Original file line numberDiff line numberDiff line change
@@ -1104,23 +1104,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
11041104
break;
11051105
}
11061106

1107-
case T_AlternativeSubPlan:
1108-
{
1109-
AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
1110-
AlternativeSubPlanState *asstate;
1111-
1112-
if (!state->parent)
1113-
elog(ERROR, "AlternativeSubPlan found with no parent plan");
1114-
1115-
asstate = ExecInitAlternativeSubPlan(asplan, state->parent);
1116-
1117-
scratch.opcode = EEOP_ALTERNATIVE_SUBPLAN;
1118-
scratch.d.alternative_subplan.asstate = asstate;
1119-
1120-
ExprEvalPushStep(state, &scratch);
1121-
break;
1122-
}
1123-
11241107
case T_FieldSelect:
11251108
{
11261109
FieldSelect *fselect = (FieldSelect *) node;

src/backend/executor/execExprInterp.c

-23
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
431431
&&CASE_EEOP_GROUPING_FUNC,
432432
&&CASE_EEOP_WINDOW_FUNC,
433433
&&CASE_EEOP_SUBPLAN,
434-
&&CASE_EEOP_ALTERNATIVE_SUBPLAN,
435434
&&CASE_EEOP_AGG_STRICT_DESERIALIZE,
436435
&&CASE_EEOP_AGG_DESERIALIZE,
437436
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
@@ -1536,14 +1535,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
15361535
EEO_NEXT();
15371536
}
15381537

1539-
EEO_CASE(EEOP_ALTERNATIVE_SUBPLAN)
1540-
{
1541-
/* too complex for an inline implementation */
1542-
ExecEvalAlternativeSubPlan(state, op, econtext);
1543-
1544-
EEO_NEXT();
1545-
}
1546-
15471538
/* evaluate a strict aggregate deserialization function */
15481539
EEO_CASE(EEOP_AGG_STRICT_DESERIALIZE)
15491540
{
@@ -3868,20 +3859,6 @@ ExecEvalSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
38683859
*op->resvalue = ExecSubPlan(sstate, econtext, op->resnull);
38693860
}
38703861

3871-
/*
3872-
* Hand off evaluation of an alternative subplan to nodeSubplan.c
3873-
*/
3874-
void
3875-
ExecEvalAlternativeSubPlan(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
3876-
{
3877-
AlternativeSubPlanState *asstate = op->d.alternative_subplan.asstate;
3878-
3879-
/* could potentially be nested, so make sure there's enough stack */
3880-
check_stack_depth();
3881-
3882-
*op->resvalue = ExecAlternativeSubPlan(asstate, econtext, op->resnull);
3883-
}
3884-
38853862
/*
38863863
* Evaluate a wholerow Var expression.
38873864
*

src/backend/executor/nodeSubplan.c

-80
Original file line numberDiff line numberDiff line change
@@ -1303,83 +1303,3 @@ ExecReScanSetParamPlan(SubPlanState *node, PlanState *parent)
13031303
parent->chgParam = bms_add_member(parent->chgParam, paramid);
13041304
}
13051305
}
1306-
1307-
1308-
/*
1309-
* ExecInitAlternativeSubPlan
1310-
*
1311-
* Initialize for execution of one of a set of alternative subplans.
1312-
*/
1313-
AlternativeSubPlanState *
1314-
ExecInitAlternativeSubPlan(AlternativeSubPlan *asplan, PlanState *parent)
1315-
{
1316-
AlternativeSubPlanState *asstate = makeNode(AlternativeSubPlanState);
1317-
double num_calls;
1318-
SubPlan *subplan1;
1319-
SubPlan *subplan2;
1320-
Cost cost1;
1321-
Cost cost2;
1322-
ListCell *lc;
1323-
1324-
asstate->subplan = asplan;
1325-
1326-
/*
1327-
* Initialize subplans. (Can we get away with only initializing the one
1328-
* we're going to use?)
1329-
*/
1330-
foreach(lc, asplan->subplans)
1331-
{
1332-
SubPlan *sp = lfirst_node(SubPlan, lc);
1333-
SubPlanState *sps = ExecInitSubPlan(sp, parent);
1334-
1335-
asstate->subplans = lappend(asstate->subplans, sps);
1336-
parent->subPlan = lappend(parent->subPlan, sps);
1337-
}
1338-
1339-
/*
1340-
* Select the one to be used. For this, we need an estimate of the number
1341-
* of executions of the subplan. We use the number of output rows
1342-
* expected from the parent plan node. This is a good estimate if we are
1343-
* in the parent's targetlist, and an underestimate (but probably not by
1344-
* more than a factor of 2) if we are in the qual.
1345-
*/
1346-
num_calls = parent->plan->plan_rows;
1347-
1348-
/*
1349-
* The planner saved enough info so that we don't have to work very hard
1350-
* to estimate the total cost, given the number-of-calls estimate.
1351-
*/
1352-
Assert(list_length(asplan->subplans) == 2);
1353-
subplan1 = (SubPlan *) linitial(asplan->subplans);
1354-
subplan2 = (SubPlan *) lsecond(asplan->subplans);
1355-
1356-
cost1 = subplan1->startup_cost + num_calls * subplan1->per_call_cost;
1357-
cost2 = subplan2->startup_cost + num_calls * subplan2->per_call_cost;
1358-
1359-
if (cost1 < cost2)
1360-
asstate->active = 0;
1361-
else
1362-
asstate->active = 1;
1363-
1364-
return asstate;
1365-
}
1366-
1367-
/*
1368-
* ExecAlternativeSubPlan
1369-
*
1370-
* Execute one of a set of alternative subplans.
1371-
*
1372-
* Note: in future we might consider changing to different subplans on the
1373-
* fly, in case the original rowcount estimate turns out to be way off.
1374-
*/
1375-
Datum
1376-
ExecAlternativeSubPlan(AlternativeSubPlanState *node,
1377-
ExprContext *econtext,
1378-
bool *isNull)
1379-
{
1380-
/* Just pass control to the active subplan */
1381-
SubPlanState *activesp = list_nth_node(SubPlanState,
1382-
node->subplans, node->active);
1383-
1384-
return ExecSubPlan(activesp, econtext, isNull);
1385-
}

src/backend/jit/llvm/llvmjit_expr.c

-6
Original file line numberDiff line numberDiff line change
@@ -1918,12 +1918,6 @@ llvm_compile_expr(ExprState *state)
19181918
LLVMBuildBr(b, opblocks[opno + 1]);
19191919
break;
19201920

1921-
case EEOP_ALTERNATIVE_SUBPLAN:
1922-
build_EvalXFunc(b, mod, "ExecEvalAlternativeSubPlan",
1923-
v_state, op, v_econtext);
1924-
LLVMBuildBr(b, opblocks[opno + 1]);
1925-
break;
1926-
19271921
case EEOP_AGG_STRICT_DESERIALIZE:
19281922
case EEOP_AGG_DESERIALIZE:
19291923
{

src/backend/jit/llvm/llvmjit_types.c

-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ void *referenced_functions[] =
102102
ExecAggTransReparent,
103103
ExecEvalAggOrderedTransDatum,
104104
ExecEvalAggOrderedTransTuple,
105-
ExecEvalAlternativeSubPlan,
106105
ExecEvalArrayCoerce,
107106
ExecEvalArrayExpr,
108107
ExecEvalConstraintCheck,

src/backend/nodes/outfuncs.c

+1
Original file line numberDiff line numberDiff line change
@@ -2254,6 +2254,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
22542254
WRITE_BOOL_FIELD(hasLateralRTEs);
22552255
WRITE_BOOL_FIELD(hasHavingQual);
22562256
WRITE_BOOL_FIELD(hasPseudoConstantQuals);
2257+
WRITE_BOOL_FIELD(hasAlternativeSubPlans);
22572258
WRITE_BOOL_FIELD(hasRecursion);
22582259
WRITE_INT_FIELD(wt_param_id);
22592260
WRITE_BITMAPSET_FIELD(curOuterRels);

src/backend/optimizer/plan/planner.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
629629
root->minmax_aggs = NIL;
630630
root->qual_security_level = 0;
631631
root->inhTargetKind = INHKIND_NONE;
632+
root->hasPseudoConstantQuals = false;
633+
root->hasAlternativeSubPlans = false;
632634
root->hasRecursion = hasRecursion;
633635
if (hasRecursion)
634636
root->wt_param_id = assign_special_exec_param(root);
@@ -759,9 +761,6 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
759761
*/
760762
root->hasHavingQual = (parse->havingQual != NULL);
761763

762-
/* Clear this flag; might get set in distribute_qual_to_rels */
763-
root->hasPseudoConstantQuals = false;
764-
765764
/*
766765
* Do expression preprocessing on targetlist and quals, as well as other
767766
* random expressions in the querytree. Note that we do not need to

0 commit comments

Comments
 (0)