Skip to content

Commit

Permalink
Mark a query's topmost Paths parallel-unsafe if they will have initPl…
Browse files Browse the repository at this point in the history
…ans.

Andreas Seltenreich found another case where we were being too optimistic
about allowing a plan to be considered parallelizable despite it containing
initPlans.  It seems like the real issue here is that if we know we are
going to tack initPlans onto the topmost Plan node for a subquery, we
had better mark that subquery's result Paths as not-parallel-safe.  That
fixes this problem and allows reversion of a kluge (added in commit
7b67a0a and extended in f24cf96) to not trust the parallel_safe flag
at top level.

Discussion: <874m2w4k5d.fsf@ex.ansel.ydns.eu>
  • Loading branch information
tglsfdc committed Nov 25, 2016
1 parent 4e026b3 commit ab77a5a
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 12 deletions.
15 changes: 6 additions & 9 deletions src/backend/optimizer/plan/planner.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,12 +341,9 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
* Optionally add a Gather node for testing purposes, provided this is
* actually a safe thing to do. (Note: we assume adding a Material node
* above did not change the parallel safety of the plan, so we can still
* rely on best_path->parallel_safe. However, that flag doesn't account
* for subplans, which we are unable to transmit to workers presently.)
* rely on best_path->parallel_safe.)
*/
if (force_parallel_mode != FORCE_PARALLEL_OFF &&
best_path->parallel_safe &&
glob->subplans == NIL)
if (force_parallel_mode != FORCE_PARALLEL_OFF && best_path->parallel_safe)
{
Gather *gather = makeNode(Gather);

Expand Down Expand Up @@ -801,10 +798,10 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
SS_identify_outer_params(root);

/*
* If any initPlans were created in this query level, increment the
* surviving Paths' costs to account for them. They won't actually get
* attached to the plan tree till create_plan() runs, but we want to be
* sure their costs are included now.
* If any initPlans were created in this query level, adjust the surviving
* Paths' costs and parallel-safety flags to account for them. The
* initPlans won't actually get attached to the plan tree till
* create_plan() runs, but we must include their effects now.
*/
final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
SS_charge_for_initplans(root, final_rel);
Expand Down
9 changes: 6 additions & 3 deletions src/backend/optimizer/plan/subselect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2128,11 +2128,13 @@ SS_identify_outer_params(PlannerInfo *root)
}

/*
* SS_charge_for_initplans - account for cost of initplans in Path costs
* SS_charge_for_initplans - account for initplans in Path costs & parallelism
*
* If any initPlans have been created in the current query level, they will
* get attached to the Plan tree created from whichever Path we select from
* the given rel; so increment all the rel's Paths' costs to account for them.
* the given rel. Increment all that rel's Paths' costs to account for them,
* and make sure the paths get marked as parallel-unsafe, since we can't
* currently transmit initPlans to parallel workers.
*
* This is separate from SS_attach_initplans because we might conditionally
* create more initPlans during create_plan(), depending on which Path we
Expand Down Expand Up @@ -2164,14 +2166,15 @@ SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
}

/*
* Now adjust the costs.
* Now adjust the costs and parallel_safe flags.
*/
foreach(lc, final_rel->pathlist)
{
Path *path = (Path *) lfirst(lc);

path->startup_cost += initplan_cost;
path->total_cost += initplan_cost;
path->parallel_safe = false;
}

/* We needn't do set_cheapest() here, caller will do it */
Expand Down

0 comments on commit ab77a5a

Please sign in to comment.