Skip to content

Commit 44ae64c

Browse files
committed
Push target list evaluation through Gather Merge.
We already do this for Gather, but it got overlooked for Gather Merge. Amit Kapila, with review and minor revisions by Rushabh Lathia and by me. Discussion: http://postgr.es/m/CAA4eK1KUC5Uyu7qaifxrjpHxbSeoQh3yzwN3bThnJsmJcZ-qtA@mail.gmail.com
1 parent e64861c commit 44ae64c

File tree

4 files changed

+69
-17
lines changed

4 files changed

+69
-17
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5060,7 +5060,8 @@ create_ordered_paths(PlannerInfo *root,
50605060
path = (Path *)
50615061
create_gather_merge_path(root, ordered_rel,
50625062
path,
5063-
target, root->sort_pathkeys, NULL,
5063+
path->pathtarget,
5064+
root->sort_pathkeys, NULL,
50645065
&total_groups);
50655066

50665067
/* Add projection step if needed */

src/backend/optimizer/util/pathnode.c

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2368,9 +2368,9 @@ create_projection_path(PlannerInfo *root,
23682368
* knows that the given path isn't referenced elsewhere and so can be modified
23692369
* in-place.
23702370
*
2371-
* If the input path is a GatherPath, we try to push the new target down to
2372-
* its input as well; this is a yet more invasive modification of the input
2373-
* path, which create_projection_path() can't do.
2371+
* If the input path is a GatherPath or GatherMergePath, we try to push the
2372+
* new target down to its input as well; this is a yet more invasive
2373+
* modification of the input path, which create_projection_path() can't do.
23742374
*
23752375
* Note that we mustn't change the source path's parent link; so when it is
23762376
* add_path'd to "rel" things will be a bit inconsistent. So far that has
@@ -2407,31 +2407,44 @@ apply_projection_to_path(PlannerInfo *root,
24072407
(target->cost.per_tuple - oldcost.per_tuple) * path->rows;
24082408

24092409
/*
2410-
* If the path happens to be a Gather path, we'd like to arrange for the
2411-
* subpath to return the required target list so that workers can help
2412-
* project. But if there is something that is not parallel-safe in the
2413-
* target expressions, then we can't.
2410+
* If the path happens to be a Gather or GatherMerge path, we'd like to
2411+
* arrange for the subpath to return the required target list so that
2412+
* workers can help project. But if there is something that is not
2413+
* parallel-safe in the target expressions, then we can't.
24142414
*/
2415-
if (IsA(path, GatherPath) &&
2415+
if ((IsA(path, GatherPath) || IsA(path, GatherMergePath)) &&
24162416
is_parallel_safe(root, (Node *) target->exprs))
24172417
{
2418-
GatherPath *gpath = (GatherPath *) path;
2419-
24202418
/*
24212419
* We always use create_projection_path here, even if the subpath is
24222420
* projection-capable, so as to avoid modifying the subpath in place.
24232421
* It seems unlikely at present that there could be any other
24242422
* references to the subpath, but better safe than sorry.
24252423
*
2426-
* Note that we don't change the GatherPath's cost estimates; it might
2424+
* Note that we don't change the parallel path's cost estimates; it might
24272425
* be appropriate to do so, to reflect the fact that the bulk of the
24282426
* target evaluation will happen in workers.
24292427
*/
2430-
gpath->subpath = (Path *)
2431-
create_projection_path(root,
2432-
gpath->subpath->parent,
2433-
gpath->subpath,
2434-
target);
2428+
if (IsA(path, GatherPath))
2429+
{
2430+
GatherPath *gpath = (GatherPath *) path;
2431+
2432+
gpath->subpath = (Path *)
2433+
create_projection_path(root,
2434+
gpath->subpath->parent,
2435+
gpath->subpath,
2436+
target);
2437+
}
2438+
else
2439+
{
2440+
GatherMergePath *gmpath = (GatherMergePath *) path;
2441+
2442+
gmpath->subpath = (Path *)
2443+
create_projection_path(root,
2444+
gmpath->subpath->parent,
2445+
gmpath->subpath,
2446+
target);
2447+
}
24352448
}
24362449
else if (path->parallel_safe &&
24372450
!is_parallel_safe(root, (Node *) target->exprs))

src/test/regress/expected/select_parallel.out

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,31 @@ select count(*) from tenk1 group by twenty;
375375
500
376376
(20 rows)
377377

378+
--test expressions in targetlist are pushed down for gather merge
379+
create or replace function simple_func(var1 integer) returns integer
380+
as $$
381+
begin
382+
return var1 + 10;
383+
end;
384+
$$ language plpgsql PARALLEL SAFE;
385+
explain (costs off, verbose)
386+
select ten, simple_func(ten) from tenk1 where ten < 100 order by ten;
387+
QUERY PLAN
388+
-----------------------------------------------------
389+
Gather Merge
390+
Output: ten, (simple_func(ten))
391+
Workers Planned: 4
392+
-> Result
393+
Output: ten, simple_func(ten)
394+
-> Sort
395+
Output: ten
396+
Sort Key: tenk1.ten
397+
-> Parallel Seq Scan on public.tenk1
398+
Output: ten
399+
Filter: (tenk1.ten < 100)
400+
(11 rows)
401+
402+
drop function simple_func(integer);
378403
--test rescan behavior of gather merge
379404
set enable_material = false;
380405
explain (costs off)

src/test/regress/sql/select_parallel.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,19 @@ explain (costs off)
144144

145145
select count(*) from tenk1 group by twenty;
146146

147+
--test expressions in targetlist are pushed down for gather merge
148+
create or replace function simple_func(var1 integer) returns integer
149+
as $$
150+
begin
151+
return var1 + 10;
152+
end;
153+
$$ language plpgsql PARALLEL SAFE;
154+
155+
explain (costs off, verbose)
156+
select ten, simple_func(ten) from tenk1 where ten < 100 order by ten;
157+
158+
drop function simple_func(integer);
159+
147160
--test rescan behavior of gather merge
148161
set enable_material = false;
149162

0 commit comments

Comments
 (0)