Skip to content

Commit 22d946b

Browse files
author
Richard Guo
committed
Consider materializing the cheapest inner path in parallel nestloop
When generating non-parallel nestloop paths for each available outer path, we always consider materializing the cheapest inner path if feasible. Similarly, in this patch, we also consider materializing the cheapest inner path when building partial nestloop paths. This approach potentially reduces the need to rescan the inner side of a partial nestloop path for each outer tuple. Author: Tender Wang Reviewed-by: Richard Guo, Robert Haas, David Rowley, Alena Rybakina Reviewed-by: Tomasz Rybak, Paul Jungwirth, Yuki Fujii Discussion: https://postgr.es/m/CAHewXNkPmtEXNfVQMou_7NqQmFABca9f4etjBtdbbm0ZKDmWvw@mail.gmail.com
1 parent 72c0b24 commit 22d946b

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

src/backend/optimizer/path/joinpath.c

+25
Original file line numberDiff line numberDiff line change
@@ -2021,11 +2021,31 @@ consider_parallel_nestloop(PlannerInfo *root,
20212021
JoinPathExtraData *extra)
20222022
{
20232023
JoinType save_jointype = jointype;
2024+
Path *inner_cheapest_total = innerrel->cheapest_total_path;
2025+
Path *matpath = NULL;
20242026
ListCell *lc1;
20252027

20262028
if (jointype == JOIN_UNIQUE_INNER)
20272029
jointype = JOIN_INNER;
20282030

2031+
/*
2032+
* Consider materializing the cheapest inner path, unless: 1) we're doing
2033+
* JOIN_UNIQUE_INNER, because in this case we have to unique-ify the
2034+
* cheapest inner path, 2) enable_material is off, 3) the cheapest inner
2035+
* path is not parallel-safe, 4) the cheapest inner path is parameterized
2036+
* by the outer rel, or 5) the cheapest inner path materializes its output
2037+
* anyway.
2038+
*/
2039+
if (save_jointype != JOIN_UNIQUE_INNER &&
2040+
enable_material && inner_cheapest_total->parallel_safe &&
2041+
!PATH_PARAM_BY_REL(inner_cheapest_total, outerrel) &&
2042+
!ExecMaterializesOutput(inner_cheapest_total->pathtype))
2043+
{
2044+
matpath = (Path *)
2045+
create_material_path(innerrel, inner_cheapest_total);
2046+
Assert(matpath->parallel_safe);
2047+
}
2048+
20292049
foreach(lc1, outerrel->partial_pathlist)
20302050
{
20312051
Path *outerpath = (Path *) lfirst(lc1);
@@ -2082,6 +2102,11 @@ consider_parallel_nestloop(PlannerInfo *root,
20822102
try_partial_nestloop_path(root, joinrel, outerpath, mpath,
20832103
pathkeys, jointype, extra);
20842104
}
2105+
2106+
/* Also consider materialized form of the cheapest inner path */
2107+
if (matpath != NULL)
2108+
try_partial_nestloop_path(root, joinrel, outerpath, matpath,
2109+
pathkeys, jointype, extra);
20852110
}
20862111
}
20872112

src/test/regress/expected/select_parallel.out

+30
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,36 @@ select count(*) from tenk1, tenk2 where tenk1.unique1 = tenk2.unique1;
653653

654654
reset enable_hashjoin;
655655
reset enable_nestloop;
656+
-- test parallel nestloop join path with materialization of the inner path
657+
alter table tenk2 set (parallel_workers = 0);
658+
explain (costs off)
659+
select * from tenk1 t1, tenk2 t2 where t1.two > t2.two;
660+
QUERY PLAN
661+
-------------------------------------------
662+
Gather
663+
Workers Planned: 4
664+
-> Nested Loop
665+
Join Filter: (t1.two > t2.two)
666+
-> Parallel Seq Scan on tenk1 t1
667+
-> Materialize
668+
-> Seq Scan on tenk2 t2
669+
(7 rows)
670+
671+
-- the joinrel is not parallel-safe due to the OFFSET clause in the subquery
672+
explain (costs off)
673+
select * from tenk1 t1, (select * from tenk2 t2 offset 0) t2 where t1.two > t2.two;
674+
QUERY PLAN
675+
-------------------------------------------
676+
Nested Loop
677+
Join Filter: (t1.two > t2.two)
678+
-> Gather
679+
Workers Planned: 4
680+
-> Parallel Seq Scan on tenk1 t1
681+
-> Materialize
682+
-> Seq Scan on tenk2 t2
683+
(7 rows)
684+
685+
alter table tenk2 reset (parallel_workers);
656686
-- test gather merge
657687
set enable_hashagg = false;
658688
explain (costs off)

src/test/regress/sql/select_parallel.sql

+10
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,16 @@ select count(*) from tenk1, tenk2 where tenk1.unique1 = tenk2.unique1;
266266
reset enable_hashjoin;
267267
reset enable_nestloop;
268268

269+
-- test parallel nestloop join path with materialization of the inner path
270+
alter table tenk2 set (parallel_workers = 0);
271+
explain (costs off)
272+
select * from tenk1 t1, tenk2 t2 where t1.two > t2.two;
273+
274+
-- the joinrel is not parallel-safe due to the OFFSET clause in the subquery
275+
explain (costs off)
276+
select * from tenk1 t1, (select * from tenk2 t2 offset 0) t2 where t1.two > t2.two;
277+
alter table tenk2 reset (parallel_workers);
278+
269279
-- test gather merge
270280
set enable_hashagg = false;
271281

0 commit comments

Comments
 (0)