Richard Guo <guofengli...@gmail.com> 于2023年9月5日周二 18:51写道:

>
> On Tue, Sep 5, 2023 at 4:52 PM tender wang <tndrw...@gmail.com> wrote:
>
>>    I recently run benchmark[1] on master, but I found performance problem
>> as below:
>> ...
>>
>> I debug the code and find consider_parallel_nestloop() doesn't consider
>> materialized form of the cheapest inner path.
>>
>
> Yeah, this seems an omission in commit 45be99f8.  I reviewed the patch
> and here are some comments.
>
> * I think we should not consider materializing the cheapest inner path
>   if we're doing JOIN_UNIQUE_INNER, because in this case we have to
>   unique-ify the inner path.
>

     That's right. The V2 patch has been fixed.


> * I think we can check if it'd be parallel safe before creating the
>   material path, thus avoid the creation in unsafe cases.
>

    Agreed.



> * I don't think the test case you added works for the code changes.
>   Maybe a plan likes below is better:
>

      Agreed.

explain (costs off)
> select * from tenk1, tenk2 where tenk1.two = tenk2.two;
>                   QUERY PLAN
> ----------------------------------------------
>  Gather
>    Workers Planned: 4
>    ->  Nested Loop
>          Join Filter: (tenk1.two = tenk2.two)
>          ->  Parallel Seq Scan on tenk1
>          ->  Materialize
>                ->  Seq Scan on tenk2
> (7 rows)
>
> Thanks
> Richard
>
From 096c645d7c8d06df3a4e6a8aa7fc4edd1c0a3755 Mon Sep 17 00:00:00 2001
From: "tender.wang" <tender.w...@openpie.com>
Date: Thu, 7 Sep 2023 17:55:04 +0800
Subject: [PATCH v2] Parallel seq scan should consider materila inner path in
 nestloop case.

---
 src/backend/optimizer/path/joinpath.c         | 19 +++++++++++++++
 src/test/regress/expected/select_parallel.out | 24 +++++++++++++++++++
 src/test/regress/sql/select_parallel.sql      |  9 +++++++
 3 files changed, 52 insertions(+)

diff --git a/src/backend/optimizer/path/joinpath.c 
b/src/backend/optimizer/path/joinpath.c
index 821d282497..87111ad643 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -2004,10 +2004,25 @@ consider_parallel_nestloop(PlannerInfo *root,
 {
        JoinType        save_jointype = jointype;
        ListCell   *lc1;
+       Path *matpath = NULL;
+       Path *inner_cheapest_total = innerrel->cheapest_total_path;
 
        if (jointype == JOIN_UNIQUE_INNER)
                jointype = JOIN_INNER;
 
+       /*
+        * Consider materializing the cheapest inner path, unless we're
+        * doing JOIN_UNIQUE_INNER or enable_material is off or the subpath
+        * is parallel unsafe or the path in question materializes its output 
anyway.
+        */
+       if (save_jointype != JOIN_UNIQUE_INNER &&
+               enable_material &&
+               inner_cheapest_total != NULL &&
+               inner_cheapest_total->parallel_safe &&
+               !ExecMaterializesOutput(inner_cheapest_total->pathtype))
+               matpath = (Path *)
+                       create_material_path(innerrel, inner_cheapest_total);
+
        foreach(lc1, outerrel->partial_pathlist)
        {
                Path       *outerpath = (Path *) lfirst(lc1);
@@ -2064,6 +2079,10 @@ consider_parallel_nestloop(PlannerInfo *root,
                                try_partial_nestloop_path(root, joinrel, 
outerpath, mpath,
                                                                                
  pathkeys, jointype, extra);
                }
+               /* Also consider materialized form of the cheapest inner path */
+               if (matpath != NULL && matpath->parallel_safe)
+                       try_partial_nestloop_path(root, joinrel, outerpath, 
matpath,
+                                                                         
pathkeys, jointype, extra);
        }
 }
 
diff --git a/src/test/regress/expected/select_parallel.out 
b/src/test/regress/expected/select_parallel.out
index d88353d496..5b9f5c58cc 100644
--- a/src/test/regress/expected/select_parallel.out
+++ b/src/test/regress/expected/select_parallel.out
@@ -844,6 +844,30 @@ select * from
 (12 rows)
 
 reset enable_material;
+-- test materialized form of the cheapest inner path
+set min_parallel_table_scan_size = '512kB';
+explain(costs off)
+select count(*) from tenk1, int4_tbl where tenk1.two < int4_tbl.f1;
+                         QUERY PLAN                         
+------------------------------------------------------------
+ Finalize Aggregate
+   ->  Gather
+         Workers Planned: 4
+         ->  Partial Aggregate
+               ->  Nested Loop
+                     Join Filter: (tenk1.two < int4_tbl.f1)
+                     ->  Parallel Seq Scan on tenk1
+                     ->  Materialize
+                           ->  Seq Scan on int4_tbl
+(9 rows)
+
+select count(*) from tenk1, int4_tbl where tenk1.two < int4_tbl.f1;
+ count 
+-------
+ 20000
+(1 row)
+
+set min_parallel_table_scan_size = 0;
 reset enable_hashagg;
 -- check parallelized int8 aggregate (bug #14897)
 explain (costs off)
diff --git a/src/test/regress/sql/select_parallel.sql 
b/src/test/regress/sql/select_parallel.sql
index 80c914dc02..0afae0c750 100644
--- a/src/test/regress/sql/select_parallel.sql
+++ b/src/test/regress/sql/select_parallel.sql
@@ -312,6 +312,15 @@ select * from
 
 reset enable_material;
 
+-- test materialized form of the cheapest inner path
+set min_parallel_table_scan_size = '512kB';
+
+explain(costs off)
+select count(*) from tenk1, int4_tbl where tenk1.two < int4_tbl.f1;
+
+select count(*) from tenk1, int4_tbl where tenk1.two < int4_tbl.f1;
+
+set min_parallel_table_scan_size = 0;
 reset enable_hashagg;
 
 -- check parallelized int8 aggregate (bug #14897)
-- 
2.25.1

Reply via email to