Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3915178

Browse files
committed
Fix testing of parallel-safety of SubPlans.
is_parallel_safe() supposed that the only relevant property of a SubPlanwas the parallel safety of the referenced subplan tree. This is wrong:the testexpr or args subtrees might contain parallel-unsafe stuff, asdemonstrated by the test case added here. However, just recursing into thesubtrees fails in a different way: we'll typically find PARAM_EXEC Paramsrepresenting the subplan's output columns in the testexpr. The previouscoding supposed that any Param must be treated as parallel-restricted, sothat a naive attempt at fixing this disabled parallel pushdown of SubPlansaltogether. We must instead determine, for any visited Param, whether itis one that would be computed by a surrounding SubPlan node; if so, it'ssafe to push down along with the SubPlan node.We might later be able to extend this logic to cope with Params used forcorrelated subplans and other cases; but that's a task for v11 or beyond.Tom Lane and Amit KapilaDiscussion:https://postgr.es/m/7064.1492022469@sss.pgh.pa.us
1 parent539f670 commit3915178

File tree

4 files changed

+57
-6
lines changed

4 files changed

+57
-6
lines changed

‎src/backend/optimizer/util/clauses.c

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ typedef struct
9393
{
9494
charmax_hazard;/* worst proparallel hazard found so far */
9595
charmax_interesting;/* worst proparallel hazard of interest */
96+
List*safe_param_ids;/* PARAM_EXEC Param IDs to treat as safe */
9697
}max_parallel_hazard_context;
9798

9899
staticboolcontain_agg_clause_walker(Node*node,void*context);
@@ -1056,6 +1057,7 @@ max_parallel_hazard(Query *parse)
10561057

10571058
context.max_hazard=PROPARALLEL_SAFE;
10581059
context.max_interesting=PROPARALLEL_UNSAFE;
1060+
context.safe_param_ids=NIL;
10591061
(void)max_parallel_hazard_walker((Node*)parse,&context);
10601062
returncontext.max_hazard;
10611063
}
@@ -1084,6 +1086,7 @@ is_parallel_safe(PlannerInfo *root, Node *node)
10841086
/* Else use max_parallel_hazard's search logic, but stop on RESTRICTED */
10851087
context.max_hazard=PROPARALLEL_SAFE;
10861088
context.max_interesting=PROPARALLEL_RESTRICTED;
1089+
context.safe_param_ids=NIL;
10871090
return !max_parallel_hazard_walker(node,&context);
10881091
}
10891092

@@ -1171,18 +1174,49 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
11711174
return true;
11721175
}
11731176

1174-
/* We can push the subplans only if they are parallel-safe. */
1177+
/*
1178+
* Only parallel-safe SubPlans can be sent to workers. Within the
1179+
* testexpr of the SubPlan, Params representing the output columns of the
1180+
* subplan can be treated as parallel-safe, so temporarily add their IDs
1181+
* to the safe_param_ids list while examining the testexpr.
1182+
*/
11751183
elseif (IsA(node,SubPlan))
1176-
return !((SubPlan*)node)->parallel_safe;
1184+
{
1185+
SubPlan*subplan= (SubPlan*)node;
1186+
List*save_safe_param_ids;
1187+
1188+
if (!subplan->parallel_safe&&
1189+
max_parallel_hazard_test(PROPARALLEL_RESTRICTED,context))
1190+
return true;
1191+
save_safe_param_ids=context->safe_param_ids;
1192+
context->safe_param_ids=list_concat(list_copy(subplan->paramIds),
1193+
context->safe_param_ids);
1194+
if (max_parallel_hazard_walker(subplan->testexpr,context))
1195+
return true;/* no need to restore safe_param_ids */
1196+
context->safe_param_ids=save_safe_param_ids;
1197+
/* we must also check args, but no special Param treatment there */
1198+
if (max_parallel_hazard_walker((Node*)subplan->args,context))
1199+
return true;
1200+
/* don't want to recurse normally, so we're done */
1201+
return false;
1202+
}
11771203

11781204
/*
11791205
* We can't pass Params to workers at the moment either, so they are also
1180-
* parallel-restricted.
1206+
* parallel-restricted, unless they are PARAM_EXEC Params listed in
1207+
* safe_param_ids, meaning they could be generated within the worker.
11811208
*/
11821209
elseif (IsA(node,Param))
11831210
{
1184-
if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED,context))
1185-
return true;
1211+
Param*param= (Param*)node;
1212+
1213+
if (param->paramkind!=PARAM_EXEC||
1214+
!list_member_int(context->safe_param_ids,param->paramid))
1215+
{
1216+
if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED,context))
1217+
return true;
1218+
}
1219+
return false;/* nothing to recurse to */
11861220
}
11871221

11881222
/*

‎src/include/nodes/primnodes.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,8 @@ typedef struct SubPlan
699699
boolunknownEqFalse;/* TRUE if it's okay to return FALSE when the
700700
* spec result is UNKNOWN; this allows much
701701
* simpler handling of null values */
702-
boolparallel_safe;/* OK to use as part of parallel plan? */
702+
boolparallel_safe;/* is the subplan parallel-safe? */
703+
/* Note: parallel_safe does not consider contents of testexpr or args */
703704
/* Information for passing params into and out of the subselect: */
704705
/* setParam and parParam are lists of integers (param IDs) */
705706
List*setParam;/* initplan subqueries have to set these

‎src/test/regress/expected/select_parallel.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,18 @@ select count(*) from tenk1 where (two, four) not in
126126
10000
127127
(1 row)
128128

129+
-- this is not parallel-safe due to use of random() within SubLink's testexpr:
130+
explain (costs off)
131+
select * from tenk1 where (unique1 + random())::integer not in
132+
(select ten from tenk2);
133+
QUERY PLAN
134+
------------------------------------
135+
Seq Scan on tenk1
136+
Filter: (NOT (hashed SubPlan 1))
137+
SubPlan 1
138+
-> Seq Scan on tenk2
139+
(4 rows)
140+
129141
alter table tenk2 reset (parallel_workers);
130142
-- test parallel index scans.
131143
set enable_seqscan to off;

‎src/test/regress/sql/select_parallel.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ explain (costs off)
4646
(select hundred, thousandfrom tenk2where thousand>100);
4747
selectcount(*)from tenk1where (two, four) notin
4848
(select hundred, thousandfrom tenk2where thousand>100);
49+
-- this is not parallel-safe due to use of random() within SubLink's testexpr:
50+
explain (costs off)
51+
select*from tenk1where (unique1+ random())::integer notin
52+
(select tenfrom tenk2);
4953
altertable tenk2 reset (parallel_workers);
5054

5155
-- test parallel index scans.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp