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

Commit b12fd41

Browse files
committed
Don't generate parallel paths for rels with parallel-restricted outputs.
Such paths are unsafe. To make it cheaper to detect when this case applies, track whether a relation's default PathTarget contains any non-Vars. In most cases, the answer will be no, which enables us to determine cheaply that the target list for a proposed path is parallel-safe. However, subquery pull-up can create cases that require us to inspect the target list more carefully. Amit Kapila, reviewed by me.
1 parent e7bcd98 commit b12fd41

File tree

5 files changed

+22
-3
lines changed

5 files changed

+22
-3
lines changed

src/backend/nodes/outfuncs.c

+1
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
20832083
WRITE_BOOL_FIELD(consider_param_startup);
20842084
WRITE_BOOL_FIELD(consider_parallel);
20852085
WRITE_NODE_FIELD(reltarget);
2086+
WRITE_BOOL_FIELD(reltarget_has_non_vars);
20862087
WRITE_NODE_FIELD(pathlist);
20872088
WRITE_NODE_FIELD(ppilist);
20882089
WRITE_NODE_FIELD(partial_pathlist);

src/backend/optimizer/path/allpaths.c

+10
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,15 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
608608
if (has_parallel_hazard((Node *) rel->baserestrictinfo, false))
609609
return;
610610

611+
/*
612+
* If the relation's outputs are not parallel-safe, we must give up.
613+
* In the common case where the relation only outputs Vars, this check is
614+
* very cheap; otherwise, we have to do more work.
615+
*/
616+
if (rel->reltarget_has_non_vars &&
617+
has_parallel_hazard((Node *) rel->reltarget->exprs, false))
618+
return;
619+
611620
/* We have a winner. */
612621
rel->consider_parallel = true;
613622
}
@@ -971,6 +980,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
971980
adjust_appendrel_attrs(root,
972981
(Node *) rel->reltarget->exprs,
973982
appinfo);
983+
childrel->reltarget_has_non_vars = rel->reltarget_has_non_vars;
974984

975985
/*
976986
* We have to make child entries in the EquivalenceClass data

src/backend/optimizer/util/placeholder.c

+2
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ add_placeholders_to_base_rels(PlannerInfo *root)
393393

394394
rel->reltarget->exprs = lappend(rel->reltarget->exprs,
395395
copyObject(phinfo->ph_var));
396+
rel->reltarget_has_non_vars = true;
396397
/* reltarget's cost and width fields will be updated later */
397398
}
398399
}
@@ -427,6 +428,7 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel,
427428
/* Yup, add it to the output */
428429
joinrel->reltarget->exprs = lappend(joinrel->reltarget->exprs,
429430
phinfo->ph_var);
431+
joinrel->reltarget_has_non_vars = true;
430432
joinrel->reltarget->width += phinfo->ph_width;
431433

432434
/*

src/backend/optimizer/util/relnode.c

+7-3
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
109109
rel->consider_parallel = false; /* might get changed later */
110110
rel->rel_parallel_workers = -1; /* set up in GetRelationInfo */
111111
rel->reltarget = create_empty_pathtarget();
112+
rel->reltarget_has_non_vars = false;
112113
rel->pathlist = NIL;
113114
rel->ppilist = NIL;
114115
rel->partial_pathlist = NIL;
@@ -396,6 +397,7 @@ build_join_rel(PlannerInfo *root,
396397
joinrel->consider_param_startup = false;
397398
joinrel->consider_parallel = false;
398399
joinrel->reltarget = create_empty_pathtarget();
400+
joinrel->reltarget_has_non_vars = false;
399401
joinrel->pathlist = NIL;
400402
joinrel->ppilist = NIL;
401403
joinrel->partial_pathlist = NIL;
@@ -506,8 +508,8 @@ build_join_rel(PlannerInfo *root,
506508
* Set the consider_parallel flag if this joinrel could potentially be
507509
* scanned within a parallel worker. If this flag is false for either
508510
* inner_rel or outer_rel, then it must be false for the joinrel also.
509-
* Even if both are true, there might be parallel-restricted quals at our
510-
* level.
511+
* Even if both are true, there might be parallel-restricted expressions
512+
* in the targetlist or quals.
511513
*
512514
* Note that if there are more than two rels in this relation, they could
513515
* be divided between inner_rel and outer_rel in any arbitrary way. We
@@ -517,7 +519,9 @@ build_join_rel(PlannerInfo *root,
517519
* here.
518520
*/
519521
if (inner_rel->consider_parallel && outer_rel->consider_parallel &&
520-
!has_parallel_hazard((Node *) restrictlist, false))
522+
!has_parallel_hazard((Node *) restrictlist, false) &&
523+
!(joinrel->reltarget_has_non_vars &&
524+
has_parallel_hazard((Node *) joinrel->reltarget->exprs, false)))
521525
joinrel->consider_parallel = true;
522526

523527
/*

src/include/nodes/relation.h

+2
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,8 @@ typedef struct RelOptInfo
490490

491491
/* default result targetlist for Paths scanning this relation */
492492
struct PathTarget *reltarget; /* list of Vars/Exprs, cost, width */
493+
bool reltarget_has_non_vars; /* true if any expression in
494+
* PathTarget is a non-Var */
493495

494496
/* materialization information */
495497
List *pathlist; /* Path structures */

0 commit comments

Comments
 (0)