From: Andrei Lepikhov <lepihov@gmail.com>
To: Ba Jinsheng <bajinsheng@u.nus.edu>
Cc: Tomas Vondra <tomas@vondra.me>
Cc: Zhang Mingli <zmlpostgres@gmail.com>
Cc: pgsql-bugs@lists.postgresql.org <pgsql-bugs@lists.postgresql.org>
Subject: Re: Question of Parallel Hash Join on TPC-H Benchmark
Date: Sun, 13 Oct 2024 10:09:29 +0700
Message-ID: <59f605ce-00f2-401b-be1e-5b684326ab6e@gmail.com> (raw)
In-Reply-To: <SEZPR06MB649483EF863B323B090986AD8A7A2@SEZPR06MB6494.apcprd06.prod.outlook.com>
References: <SEZPR06MB64945FE5A48A367A8C0EE8FC8A782@SEZPR06MB6494.apcprd06.prod.outlook.com>
<SEZPR06MB6494C5B80077EC08B21772888A782@SEZPR06MB6494.apcprd06.prod.outlook.com>
<20f9671d-6f40-429b-a749-a2f53086e0dd@vondra.me>
<3c7df680-97e6-4f20-ab27-65fb8282f95e@Spark>
<SEZPR06MB6494BD3DDF5B03700032C2C98A782@SEZPR06MB6494.apcprd06.prod.outlook.com>
<978176f8-14a5-4f4d-8925-07d2e7dec4ce@gmail.com>
<SEZPR06MB649483EF863B323B090986AD8A7A2@SEZPR06MB6494.apcprd06.prod.outlook.com>
On 13/10/2024 01:11, Ba Jinsheng wrote:
> I changed the code to generate an efficient query plan (only the
> HashJoin in fifth line is in parallel), so I am wondering whether it is
> possible to optimize the code to enable this efficient query plan in
> default? I believe at least, it would improve the performance of
> PostgreSQL on the standard benchmark TPC-H.
> If you need, I can provide my environment in docker for your analysis.
Thanks for the case! It was a pretty exciting case.
The answer to your question is simple: we have a correlated subquery
here with the clause: 'p_partkey = ps_partkey'. Because of that, the top
JOIN operator has parameterised inner, and parallel workers can't be
used according to the current state of the code. See comments in the code:
/*
* If the inner path is parameterised, we can't use a partial hashjoin.
* Parameterised partial paths are not supported. The caller should
* already have verified that no lateral rels are required here.
*/
Even if you transform the subquery to SEMI JOIN, you will have a
parameterised join, and the parallel plan will be declined.
So, the best you can do here is replace clause
'ps_supplycost = (SELECT ...)' with 'ps_supplycost IN (SELECT ...)'
I got quite a beneficial speedup there (see attached).
So, what can we improve here?
- I am suspicious about the parallel plans for parameterised paths, at
least soon.
- Improve pull-ups for subqueries. Especially if we can prove that the
subquery has a single aggregate returning only one tuple. It looks doable.
--
regards, Andrei Lepikhov
Attachments:final_explain.txt (text/plain, 6.6K) download
Limit (cost=612.17..10889.47 rows=100 width=192) (actual time=108.807..141.876 rows=100 loops=1)
-> Incremental Sort (cost=612.17..20858.46 rows=197 width=192) (actual time=108.804..141.863 rows=100 loops=1)
Sort Key: supplier.s_acctbal DESC, nation.n_name, supplier.s_name, part.p_partkey
Presorted Key: supplier.s_acctbal, nation.n_name, supplier.s_name
Full-sort Groups: 4 Sort Method: quicksort Average Memory: 33kB Peak Memory: 33kB
-> Nested Loop (cost=508.91..20849.59 rows=197 width=192) (actual time=96.504..141.737 rows=101 loops=1)
Join Filter: (supplier.s_suppkey = partsupp.ps_suppkey)
Rows Removed by Join Filter: 209606
-> Gather Merge (cost=359.76..1005.71 rows=606 width=166) (actual time=10.099..10.312 rows=433 loops=1)
Workers Planned: 5
Workers Launched: 5
-> Sort (cost=259.68..259.99 rows=121 width=166) (actual time=1.568..1.583 rows=72 loops=6)
Sort Key: supplier.s_acctbal DESC, nation.n_name, supplier.s_name
Sort Method: quicksort Memory: 422kB
Worker 0: Sort Method: quicksort Memory: 25kB
Worker 1: Sort Method: quicksort Memory: 25kB
Worker 2: Sort Method: quicksort Memory: 25kB
Worker 3: Sort Method: quicksort Memory: 25kB
Worker 4: Sort Method: quicksort Memory: 25kB
-> Parallel Hash Join (cost=2.30..255.50 rows=121 width=166) (actual time=0.066..1.085 rows=334 loops=6)
Hash Cond: (supplier.s_nationkey = nation.n_nationkey)
-> Parallel Seq Scan on supplier (cost=0.00..243.00 rows=2060 width=144) (actual time=0.005..2.074 rows=10000 loops=1)
-> Parallel Hash (cost=2.27..2.27 rows=3 width=30) (actual time=0.042..0.043 rows=1 loops=6)
Buckets: 1024 Batches: 1 Memory Usage: 40kB
-> Parallel Hash Join (cost=1.05..2.27 rows=3 width=30) (actual time=0.089..0.124 rows=5 loops=1)
Hash Cond: (nation.n_regionkey = region.r_regionkey)
-> Parallel Seq Scan on nation (cost=0.00..1.15 rows=14 width=34) (actual time=0.004..0.008 rows=25 loops=1)
-> Parallel Hash (cost=1.04..1.04 rows=1 width=4) (actual time=0.025..0.026 rows=1 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 40kB
-> Parallel Seq Scan on region (cost=0.00..1.04 rows=1 width=4) (actual time=0.014..0.016 rows=1 loops=1)
Filter: (r_name = 'ASIA'::bpchar)
Rows Removed by Filter: 4
-> Materialize (cost=149.15..15436.44 rows=485 width=34) (actual time=0.002..0.234 rows=484 loops=433)
Storage: Memory Maximum Storage: 51kB
-> Nested Loop (cost=149.15..15434.02 rows=485 width=34) (actual time=0.846..84.831 rows=485 loops=1)
-> Gather (cost=100.00..5421.00 rows=826 width=30) (actual time=0.412..20.567 rows=826 loops=1)
Workers Planned: 8
Workers Launched: 3
-> Parallel Seq Scan on part (cost=0.00..4495.00 rows=103 width=30) (actual time=0.139..25.150 rows=206 loops=4)
Filter: (((p_type)::text ~~ '%STEEL'::text) AND (p_size = 30))
Rows Removed by Filter: 49794
-> Hash Join (cost=49.15..61.20 rows=1 width=8) (actual time=0.073..0.074 rows=1 loops=826)
Hash Cond: (partsupp.ps_supplycost = (min(partsupp_1.ps_supplycost)))
-> Index Scan using partsupp_pkey on partsupp (cost=0.42..12.47 rows=4 width=14) (actual time=0.008..0.010 rows=4 loops=485)
Index Cond: (ps_partkey = part.p_partkey)
-> Hash (cost=48.71..48.71 rows=1 width=32) (actual time=0.064..0.064 rows=1 loops=826)
Buckets: 1024 Batches: 1 Memory Usage: 9kB
-> Aggregate (cost=48.70..48.71 rows=1 width=32) (actual time=0.063..0.063 rows=1 loops=826)
-> Nested Loop (cost=0.85..48.70 rows=1 width=6) (actual time=0.046..0.059 rows=1 loops=826)
Join Filter: (region_1.r_regionkey = nation_1.n_regionkey)
Rows Removed by Join Filter: 3
-> Seq Scan on region region_1 (cost=0.00..1.06 rows=1 width=4) (actual time=0.003..0.004 rows=1 loops=826)
Filter: (r_name = 'ASIA'::bpchar)
Rows Removed by Filter: 4
-> Nested Loop (cost=0.85..47.59 rows=4 width=10) (actual time=0.021..0.054 rows=4 loops=826)
-> Nested Loop (cost=0.71..46.96 rows=4 width=10) (actual time=0.017..0.038 rows=4 loops=826)
-> Index Scan using partsupp_pkey on partsupp partsupp_1 (cost=0.42..13.75 rows=4 width=10) (actual time=0.010..0.012 rows=4 loops=826)
Index Cond: (ps_partkey = part.p_partkey)
-> Index Scan using supplier_pkey on supplier supplier_1 (cost=0.29..8.30 rows=1 width=8) (actual time=0.005..0.005 rows=1 loops=3304)
Index Cond: (s_suppkey = partsupp_1.ps_suppkey)
-> Index Scan using nation_pkey on nation nation_1 (cost=0.14..0.16 rows=1 width=8) (actual time=0.003..0.003 rows=1 loops=3304)
Index Cond: (n_nationkey = supplier_1.s_nationkey)
Planning Time: 14.975 ms
Execution Time: 144.161 ms
(64 rows)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-bugs@postgresql.org
Cc: lepihov@gmail.com, bajinsheng@u.nus.edu, tomas@vondra.me, zmlpostgres@gmail.com, pgsql-bugs@lists.postgresql.org
Subject: Re: Question of Parallel Hash Join on TPC-H Benchmark
In-Reply-To: <59f605ce-00f2-401b-be1e-5b684326ab6e@gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox