์ต์ CPU์๋ ๋ง์ ์ฝ์ด๊ฐ ์์ต๋๋ค. ์๋
๋์ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฟผ๋ฆฌ๋ฅผ ๋ณ๋ ฌ๋ก ์ ์กํด ์์ต๋๋ค. ํ
์ด๋ธ์ ์ฌ๋ฌ ํ์ ๋ํ ๋ณด๊ณ ์ ์ฟผ๋ฆฌ์ธ ๊ฒฝ์ฐ ์ฌ๋ฌ CPU๋ฅผ ์ฌ์ฉํ ๋ ๋ ๋น ๋ฅด๊ฒ ์คํ๋๋ฉฐ PostgreSQL์ ๋ฒ์ 9.6๋ถํฐ ์ด๋ฅผ ์ํํ ์ ์์์ต๋๋ค.
๋ณ๋ ฌ ์ฟผ๋ฆฌ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ ๋ฐ 3๋ ์ด ๊ฑธ๋ ธ์ต๋๋ค. ์ฟผ๋ฆฌ ์คํ์ ์ฌ๋ฌ ๋จ๊ณ์์ ์ฝ๋๋ฅผ ๋ค์ ์์ฑํด์ผ ํ์ต๋๋ค. PostgreSQL 9.6์ ์ฝ๋๋ฅผ ๋์ฑ ๊ฐ์ ํ๊ธฐ ์ํด ์ธํ๋ผ๋ฅผ ๋์ ํ์ต๋๋ค. ํ์ ๋ฒ์ ์์๋ ๋ค๋ฅธ ์ ํ์ ์ฟผ๋ฆฌ๊ฐ ๋ณ๋ ฌ๋ก ์คํ๋ฉ๋๋ค.
์ ํ
- ๋ชจ๋ ์ฝ์ด๊ฐ ์ด๋ฏธ ์ฌ์ฉ ์ค์ธ ๊ฒฝ์ฐ ๋ณ๋ ฌ ์คํ์ ํ์ฑํํ์ง ๋ง์ญ์์ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ๋ค๋ฅธ ์์ฒญ์ด ๋๋ ค์ง๋๋ค.
- ๊ฐ์ฅ ์ค์ํ ๊ฒ์ WORK_MEM ๊ฐ์ด ๋์ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ ๋ง์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค๋ ๊ฒ์ ๋๋ค. ๊ฐ ํด์ ์กฐ์ธ ๋๋ ์ ๋ ฌ์ work_mem ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฐจ์งํฉ๋๋ค.
- ๋๊ธฐ ์๊ฐ์ด ์งง์ OLTP ์ฟผ๋ฆฌ๋ ๋ณ๋ ฌ ์คํ์ผ๋ก ๊ฐ์ํ๋ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฟผ๋ฆฌ๊ฐ ํ๋์ ํ์ ๋ฐํํ๋ ๊ฒฝ์ฐ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ก ์ธํด ์๋๊ฐ ๋๋ ค์ง ๋ฟ์ ๋๋ค.
- ๊ฐ๋ฐ์๋ TPC-H ๋ฒค์น๋งํฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ข์ํฉ๋๋ค. ์ด์ฉ๋ฉด ์๋ฒฝํ ๋ณ๋ ฌ ์คํ์ ์ํด ๋น์ทํ ์ฟผ๋ฆฌ๊ฐ ์์ ์๋ ์์ต๋๋ค.
- ์กฐ๊ฑด์ ์ ๊ธ์ด ์๋ SELECT ์ฟผ๋ฆฌ๋ง ๋ณ๋ ฌ๋ก ์คํ๋ฉ๋๋ค.
- ๋๋ก๋ ์ ์ ํ ์ธ๋ฑ์ฑ์ด ๋ณ๋ ฌ ๋ชจ๋์์ ์์ฐจ์ ํ ์ด๋ธ ์ค์บ๋ณด๋ค ๋ ๋์ ๋๋ ์์ต๋๋ค.
- ์ฟผ๋ฆฌ ๋ฐ ์ปค์ ์ผ์ ์ค์ง๋ ์ง์๋์ง ์์ต๋๋ค.
- ์ฐฝ ํจ์์ ์์ ์งํฉ ์ง๊ณ ํจ์๋ ๋ณ๋ ฌ์ด ์๋๋๋ค.
- I/O ์ํฌ๋ก๋์์๋ ์๋ฌด ๊ฒ๋ ์ป์ ์ ์์ต๋๋ค.
- ๋ณ๋ ฌ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ ๋ ฌ์ด ํฌํจ๋ ์ฟผ๋ฆฌ๋ ์ผ๋ถ ์ธก๋ฉด์์ ๋ณ๋ ฌ๋ก ์คํ๋ ์ ์์ต๋๋ค.
- ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ํ์ฑํํ๋ ค๋ฉด CTE (WITH ...)๋ฅผ ์ค์ฒฉ๋ SELECT๋ก ๋ฐ๊พธ์ธ์.
- ํ์ฌ ๋ฐ์ดํฐ ๋ํผ๋ ์์ง ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ์ง์ํ์ง ์์ต๋๋ค(๊ทธ๋ฌ๋ ๊ฐ๋ฅํฉ๋๋ค!).
- FULL OUTER JOIN์ ์ง์๋์ง ์์ต๋๋ค.
- max_rows๋ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ๋นํ์ฑํํฉ๋๋ค.
- ์ฟผ๋ฆฌ์ PARALLEL SAFE๋ก ํ์๋์ง ์์ ํจ์๊ฐ ์๋ ๊ฒฝ์ฐ ๋จ์ผ ์ค๋ ๋๊ฐ ๋ฉ๋๋ค.
- SERIALIZABLE ํธ๋์ญ์ ๊ฒฉ๋ฆฌ ์์ค์ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ๋นํ์ฑํํฉ๋๋ค.
ํ ์คํธ ํ๊ฒฝ
PostgreSQL ๊ฐ๋ฐ์๋ TPC-H ๋ฒค์น๋งํฌ ์ฟผ๋ฆฌ์ ์๋ต ์๊ฐ์ ์ค์ด๋ ค๊ณ ๋
ธ๋ ฅํ์ต๋๋ค. ๋ฒค์น๋งํฌ๋ฅผ ๋ค์ด๋ก๋ํ๊ณ
- TPC-H_Tools_v2.17.3.zip(๋๋ ์ต์ ๋ฒ์ ) ๋ค์ด๋ก๋
TPC ์คํ์ฌ์ดํธ์์ . - makefile.suite์ ์ด๋ฆ์ Makefile๋ก ๋ฐ๊พธ๊ณ ์ฌ๊ธฐ์ ์ค๋ช
๋ ๋๋ก ๋ณ๊ฒฝํฉ๋๋ค.
https://github.com/tvondra/pg_tpch . make ๋ช ๋ น์ ์ฌ์ฉํ์ฌ ์ฝ๋๋ฅผ ์ปดํ์ผํฉ๋๋ค. - ๋ฐ์ดํฐ ์์ฑ:
./dbgen -s 10
23GB ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์์ฑํฉ๋๋ค. ์ด๋ ๋ณ๋ ฌ ์ฟผ๋ฆฌ์ ๋น๋ณ๋ ฌ ์ฟผ๋ฆฌ์ ์ฑ๋ฅ ์ฐจ์ด๋ฅผ ํ์ธํ๊ธฐ์ ์ถฉ๋ถํฉ๋๋ค. - ํ์ผ ๋ณํ
tbl
ะฒcsv ั for
ะธsed
. - ์ ์ฅ์ ๋ณต์
pg_tpch
๊ทธ๋ฆฌ๊ณ ํ์ผ์ ๋ณต์ฌํ์ธ์csv
ะฒpg_tpch/dss/data
. - ๋ช
๋ น์ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ ๋ง๋ค๊ธฐ
qgen
. - ๋ค์ ๋ช
๋ น์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํฉ๋๋ค.
./tpch.sh
.
๋ณ๋ ฌ ์์ฐจ ์ค์บ๋
๋ณ๋ ฌ ์ฝ๊ธฐ ๋๋ฌธ์ด ์๋๋ผ ๋ฐ์ดํฐ๊ฐ ๋ง์ CPU ์ฝ์ด์ ๋ถ์ฐ๋์ด ์๊ธฐ ๋๋ฌธ์ ๋ ๋น ๋ฅผ ์ ์์ต๋๋ค. ์ต์ ์ด์ ์ฒด์ ์์๋ PostgreSQL ๋ฐ์ดํฐ ํ์ผ์ด ์ ์บ์๋ฉ๋๋ค. ๋ฏธ๋ฆฌ ์ฝ๊ธฐ๋ฅผ ์ฌ์ฉํ๋ฉด PG ๋ฐ๋ชฌ์ด ์์ฒญํ๋ ๊ฒ๋ณด๋ค ์คํ ๋ฆฌ์ง์์ ๋ ํฐ ๋ธ๋ก์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ์ฟผ๋ฆฌ ์ฑ๋ฅ์ ๋์คํฌ I/O์ ์ํด ์ ํ๋์ง ์์ต๋๋ค. ๋ค์์ ์ํด CPU ์ฃผ๊ธฐ๋ฅผ ์๋นํฉ๋๋ค.
- ํ ์ด๋ธ ํ์ด์ง์์ ํ ๋ฒ์ ํ๋์ฉ ํ์ ์ฝ์ต๋๋ค.
- ๋ฌธ์์ด ๊ฐ๊ณผ ์กฐ๊ฑด ๋น๊ต
WHERE
.
๊ฐ๋จํ ์ฟผ๋ฆฌ๋ฅผ ์คํํด ๋ณด๊ฒ ์ต๋๋ค. select
:
tpch=# explain analyze select l_quantity as sum_qty from lineitem where l_shipdate <= date '1998-12-01' - interval '105' day;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
Seq Scan on lineitem (cost=0.00..1964772.00 rows=58856235 width=5) (actual time=0.014..16951.669 rows=58839715 loops=1)
Filter: (l_shipdate <= '1998-08-18 00:00:00'::timestamp without time zone)
Rows Removed by Filter: 1146337
Planning Time: 0.203 ms
Execution Time: 19035.100 ms
์์ฐจ ์ค์บ์ ์ง๊ณ ์์ด ๋๋ฌด ๋ง์ ํ์ ์์ฑํ๋ฏ๋ก ์ฟผ๋ฆฌ๊ฐ ๋จ์ผ CPU ์ฝ์ด์ ์ํด ์คํ๋ฉ๋๋ค.
์ถ๊ฐํ๋ฉด SUM()
, ๋ ๊ฐ์ง ์ํฌํ๋ก๊ฐ ์ฟผ๋ฆฌ ์๋๋ฅผ ๋์ด๋ ๋ฐ ๋์์ด ๋๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
explain analyze select sum(l_quantity) as sum_qty from lineitem where l_shipdate <= date '1998-12-01' - interval '105' day;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------
Finalize Aggregate (cost=1589702.14..1589702.15 rows=1 width=32) (actual time=8553.365..8553.365 rows=1 loops=1)
-> Gather (cost=1589701.91..1589702.12 rows=2 width=32) (actual time=8553.241..8555.067 rows=3 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Partial Aggregate (cost=1588701.91..1588701.92 rows=1 width=32) (actual time=8547.546..8547.546 rows=1 loops=3)
-> Parallel Seq Scan on lineitem (cost=0.00..1527393.33 rows=24523431 width=5) (actual time=0.038..5998.417 rows=19613238 loops=3)
Filter: (l_shipdate <= '1998-08-18 00:00:00'::timestamp without time zone)
Rows Removed by Filter: 382112
Planning Time: 0.241 ms
Execution Time: 8555.131 ms
๋ณ๋ ฌ ์ง๊ณ
๋ณ๋ ฌ ์ํ์ค ์ค์บ ๋
ธ๋๋ ๋ถ๋ถ ์ง๊ณ๋ฅผ ์ํ ํ์ ์์ฑํฉ๋๋ค. "๋ถ๋ถ ์ง๊ณ" ๋
ธ๋๋ ๋ค์์ ์ฌ์ฉํ์ฌ ์ด๋ฌํ ์ ์ ์๋ฆ
๋๋ค. SUM()
. ๋ง์ง๋ง์๋ ๊ฐ ์์
์ ํ๋ก์ธ์ค์ SUM ์นด์ดํฐ๊ฐ "Gather" ๋
ธ๋์ ์ํด ์์ง๋ฉ๋๋ค.
์ต์ข ๊ฒฐ๊ณผ๋ "Finalize Aggregate" ๋ ธ๋์ ์ํด ๊ณ์ฐ๋ฉ๋๋ค. ์์ ๋ง์ ์ง๊ณ ํจ์๊ฐ ์๋ ๊ฒฝ์ฐ ์ด๋ฅผ "๋ณ๋ ฌ ์์ "์ผ๋ก ํ์ํ๋ ๊ฒ์ ์์ง ๋ง์ธ์.
์์ ์ ํ๋ก์ธ์ค ์
์๋ฒ๋ฅผ ๋ค์ ์์ํ์ง ์๊ณ ๋ ์์ ์ ํ๋ก์ธ์ค ์๋ฅผ ๋๋ฆด ์ ์์ต๋๋ค.
explain analyze select sum(l_quantity) as sum_qty from lineitem where l_shipdate <= date '1998-12-01' - interval '105' day;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------
Finalize Aggregate (cost=1589702.14..1589702.15 rows=1 width=32) (actual time=8553.365..8553.365 rows=1 loops=1)
-> Gather (cost=1589701.91..1589702.12 rows=2 width=32) (actual time=8553.241..8555.067 rows=3 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Partial Aggregate (cost=1588701.91..1588701.92 rows=1 width=32) (actual time=8547.546..8547.546 rows=1 loops=3)
-> Parallel Seq Scan on lineitem (cost=0.00..1527393.33 rows=24523431 width=5) (actual time=0.038..5998.417 rows=19613238 loops=3)
Filter: (l_shipdate <= '1998-08-18 00:00:00'::timestamp without time zone)
Rows Removed by Filter: 382112
Planning Time: 0.241 ms
Execution Time: 8555.131 ms
์ฌ๊ธฐ์ ๋ฌด์จ ์ผ์ด ์ผ์ด๋๊ณ ์๋ ๊ฑธ๊น์? ์์ ํ๋ก์ธ์ค๋ 2๋ฐฐ ๋์ด๋ฌ๊ณ ์์ฒญ ์๋๋ 1,6599๋ฐฐ ๋นจ๋ผ์ก์ต๋๋ค. ๊ณ์ฐ์ด ํฅ๋ฏธ๋กญ์ต๋๋ค. 2๊ฐ์ ์์ ์ ํ๋ก์ธ์ค์ 1๊ฐ์ ๋ฆฌ๋๊ฐ ์์์ต๋๋ค. ๋ณ๊ฒฝ ํ 4+1์ด ๋์์ต๋๋ค.
๋ณ๋ ฌ ์ฒ๋ฆฌ๋ก ์ธํ ์ต๋ ์๋ ํฅ์: 5/3 = 1,66(6)๋ฐฐ.
์ด๋ป๊ฒ ์๋ํฉ๋๊น?
ํ๋ก์ธ์ค
์์ฒญ ์คํ์ ํญ์ ์ ํ ํ๋ก์ธ์ค์์ ์์๋ฉ๋๋ค. ๋ฆฌ๋๋ ๋ชจ๋ ๋น๋ณ๋ ฌ ์ฒ๋ฆฌ์ ์ผ๋ถ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ์ํํฉ๋๋ค. ๋์ผํ ์์ฒญ์ ์ํํ๋ ๋ค๋ฅธ ํ๋ก์ธ์ค๋ฅผ ์์
์ ํ๋ก์ธ์ค๋ผ๊ณ ํฉ๋๋ค. ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ ์ธํ๋ผ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ํธ ์์ฉ
์์ ์ ํ๋ก์ธ์ค๋ ๋ฉ์์ง ๋๊ธฐ์ด(๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฐ)์ ํตํด ๋ฆฌ๋์ ํต์ ํฉ๋๋ค. ๊ฐ ํ๋ก์ธ์ค์๋ ์ค๋ฅ์ฉ ๋๊ธฐ์ด๊ณผ ํํ์ฉ ๋๊ธฐ์ด์ด 2๊ฐ ์์ต๋๋ค.
์ผ๋ง๋ ๋ง์ ์ํฌํ๋ก๊ฐ ํ์ํฉ๋๊น?
์ต์ ํ๋๋ ๋งค๊ฐ๋ณ์๋ก ์ง์ ๋ฉ๋๋ค. max_parallel_workers_per_gather
max_parallel_workers size
max_worker_processes
์์ ์ ํ๋ก์ธ์ค๋ฅผ ํ ๋นํ ์ ์๋ ๊ฒฝ์ฐ ์ฒ๋ฆฌ๋ ๋จ์ผ ํ๋ก์ธ์ค๋ก ์ํ๋ฉ๋๋ค.
์ฟผ๋ฆฌ ํ๋๋๋ ํ
์ด๋ธ์ด๋ ์ธ๋ฑ์ค์ ํฌ๊ธฐ์ ๋ฐ๋ผ ์ํฌํ๋ก๋ฅผ ์ค์ผ ์ ์์ต๋๋ค. ์ด์ ๋ํ ๋งค๊ฐ๋ณ์๊ฐ ์์ต๋๋ค. min_parallel_table_scan_size
min_parallel_index_scan_size
set min_parallel_table_scan_size='8MB'
8MB table => 1 worker
24MB table => 2 workers
72MB table => 3 workers
x => log(x / min_parallel_table_scan_size) / log(3) + 1 worker
ํ
์ด๋ธ์ด 3๋ฐฐ ๋ ์ปค์ง ๋๋ง๋ค min_parallel_(index|table)_scan_size
, Postgres๋ ์์
์ ํ๋ก์ธ์ค๋ฅผ ์ถ๊ฐํฉ๋๋ค. ์ํฌํ๋ก ์๋ ๋น์ฉ์ ๊ธฐ์ค์ผ๋ก ํ์ง ์์ต๋๋ค. ์ํ ์ข
์์ฑ์ ๋ณต์กํ ๊ตฌํ์ ์ด๋ ต๊ฒ ๋ง๋ญ๋๋ค. ๋์ ํ๋๋๋ ๊ฐ๋จํ ๊ท์น์ ์ฌ์ฉํฉ๋๋ค.
์ค์ ๋ก ์ด๋ฌํ ๊ท์น์ ํญ์ ํ๋ก๋์
์ ์ ํฉํ ๊ฒ์ ์๋๋ฏ๋ก ํน์ ํ
์ด๋ธ์ ๋ํ ์์
์ ํ๋ก์ธ์ค ์๋ฅผ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. ALTER TABLE ... SET (parallel_workers = N
).
๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ง ์๋ ์ด์ ๋ ๋ฌด์์ ๋๊น?
๊ธด ์ ํ ์ฌํญ ๋ชฉ๋ก ์ธ์๋ ๋น์ฉ ํ์ธ๋ ์์ต๋๋ค.
parallel_setup_cost
parallel_tuple_cost
์ค์ฒฉ๋ ๋ฃจํ ์กฐ์ธ
PostgreSQL 9.6+ ะผะพะถะตั ะฒัะฟะพะปะฝััั ะฒะปะพะถะตะฝะฝัะต ัะธะบะปั ะฟะฐัะฐะปะปะตะปัะฝะพ โ ััะพ ะฟัะพััะฐั ะพะฟะตัะฐัะธั.
explain (costs off) select c_custkey, count(o_orderkey)
from customer left outer join orders on
c_custkey = o_custkey and o_comment not like '%special%deposits%'
group by c_custkey;
QUERY PLAN
--------------------------------------------------------------------------------------
Finalize GroupAggregate
Group Key: customer.c_custkey
-> Gather Merge
Workers Planned: 4
-> Partial GroupAggregate
Group Key: customer.c_custkey
-> Nested Loop Left Join
-> Parallel Index Only Scan using customer_pkey on customer
-> Index Scan using idx_orders_custkey on orders
Index Cond: (customer.c_custkey = o_custkey)
Filter: ((o_comment)::text !~~ '%special%deposits%'::text)
์์ง์ ๋ง์ง๋ง ๋จ๊ณ์์ ๋ฐ์ํ๋ฏ๋ก Nested Loop Left Join์ ๋ณ๋ ฌ ์์
์
๋๋ค. ๋ณ๋ ฌ ์ธ๋ฑ์ค ์ ์ฉ ์ค์บ์ ๋ฒ์ 10์์๋ง ๋์
๋์์ต๋๋ค. ๋ณ๋ ฌ ์ง๋ ฌ ์ค์บ๊ณผ ์ ์ฌํ๊ฒ ์๋ํฉ๋๋ค. ์ํ c_custkey = o_custkey
ํด๋ผ์ด์ธํธ ๋ฌธ์์ด๋น ํ๋์ ์ฃผ๋ฌธ์ ์ฝ์ต๋๋ค. ๋ฐ๋ผ์ ํํํ์ง ์์ต๋๋ค.
ํด์ ์กฐ์ธ
PostgreSQL 11๊น์ง ๊ฐ ์์ ์ ํ๋ก์ธ์ค๋ ์์ฒด ํด์ ํ ์ด๋ธ์ ์์ฑํฉ๋๋ค. ์ด๋ฌํ ํ๋ก์ธ์ค๊ฐ XNUMX๊ฐ ์ด์ ์์ผ๋ฉด ์ฑ๋ฅ์ด ํฅ์๋์ง ์์ต๋๋ค. ์ ๋ฒ์ ์์๋ ํด์ ํ ์ด๋ธ์ด ๊ณต์ ๋ฉ๋๋ค. ๊ฐ ์์ ์ ํ๋ก์ธ์ค๋ WORK_MEM์ ์ฌ์ฉํ์ฌ ํด์ ํ ์ด๋ธ์ ์์ฑํ ์ ์์ต๋๋ค.
select
l_shipmode,
sum(case
when o_orderpriority = '1-URGENT'
or o_orderpriority = '2-HIGH'
then 1
else 0
end) as high_line_count,
sum(case
when o_orderpriority <> '1-URGENT'
and o_orderpriority <> '2-HIGH'
then 1
else 0
end) as low_line_count
from
orders,
lineitem
where
o_orderkey = l_orderkey
and l_shipmode in ('MAIL', 'AIR')
and l_commitdate < l_receiptdate
and l_shipdate < l_commitdate
and l_receiptdate >= date '1996-01-01'
and l_receiptdate < date '1996-01-01' + interval '1' year
group by
l_shipmode
order by
l_shipmode
LIMIT 1;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=1964755.66..1964961.44 rows=1 width=27) (actual time=7579.592..7922.997 rows=1 loops=1)
-> Finalize GroupAggregate (cost=1964755.66..1966196.11 rows=7 width=27) (actual time=7579.590..7579.591 rows=1 loops=1)
Group Key: lineitem.l_shipmode
-> Gather Merge (cost=1964755.66..1966195.83 rows=28 width=27) (actual time=7559.593..7922.319 rows=6 loops=1)
Workers Planned: 4
Workers Launched: 4
-> Partial GroupAggregate (cost=1963755.61..1965192.44 rows=7 width=27) (actual time=7548.103..7564.592 rows=2 loops=5)
Group Key: lineitem.l_shipmode
-> Sort (cost=1963755.61..1963935.20 rows=71838 width=27) (actual time=7530.280..7539.688 rows=62519 loops=5)
Sort Key: lineitem.l_shipmode
Sort Method: external merge Disk: 2304kB
Worker 0: Sort Method: external merge Disk: 2064kB
Worker 1: Sort Method: external merge Disk: 2384kB
Worker 2: Sort Method: external merge Disk: 2264kB
Worker 3: Sort Method: external merge Disk: 2336kB
-> Parallel Hash Join (cost=382571.01..1957960.99 rows=71838 width=27) (actual time=7036.917..7499.692 rows=62519 loops=5)
Hash Cond: (lineitem.l_orderkey = orders.o_orderkey)
-> Parallel Seq Scan on lineitem (cost=0.00..1552386.40 rows=71838 width=19) (actual time=0.583..4901.063 rows=62519 loops=5)
Filter: ((l_shipmode = ANY ('{MAIL,AIR}'::bpchar[])) AND (l_commitdate < l_receiptdate) AND (l_shipdate < l_commitdate) AND (l_receiptdate >= '1996-01-01'::date) AND (l_receiptdate < '1997-01-01 00:00:00'::timestamp without time zone))
Rows Removed by Filter: 11934691
-> Parallel Hash (cost=313722.45..313722.45 rows=3750045 width=20) (actual time=2011.518..2011.518 rows=3000000 loops=5)
Buckets: 65536 Batches: 256 Memory Usage: 3840kB
-> Parallel Seq Scan on orders (cost=0.00..313722.45 rows=3750045 width=20) (actual time=0.029..995.948 rows=3000000 loops=5)
Planning Time: 0.977 ms
Execution Time: 7923.770 ms
TPC-H์ ์ฟผ๋ฆฌ 12๋ ๋ณ๋ ฌ ํด์ ์ฐ๊ฒฐ์ ๋ช ํํ๊ฒ ๋ณด์ฌ์ค๋๋ค. ๊ฐ ์์ ์ ํ๋ก์ธ์ค๋ ๊ณตํต ํด์ ํ ์ด๋ธ ์์ฑ์ ๊ธฐ์ฌํฉ๋๋ค.
๋ณํฉ ์กฐ์ธ
๋ณํฉ ์กฐ์ธ์ ๋ณธ์ง์ ์ผ๋ก ๋น๋ณ๋ ฌ์ ์ ๋๋ค. ์ด๊ฒ์ด ์ฟผ๋ฆฌ์ ๋ง์ง๋ง ๋จ๊ณ์ด๋๋ผ๋ ๊ฑฑ์ ํ์ง ๋ง์ธ์. ์ฌ์ ํ ๋ณ๋ ฌ๋ก ์คํ๋ ์ ์์ต๋๋ค.
-- Query 2 from TPC-H
explain (costs off) select s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment
from part, supplier, partsupp, nation, region
where
p_partkey = ps_partkey
and s_suppkey = ps_suppkey
and p_size = 36
and p_type like '%BRASS'
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = 'AMERICA'
and ps_supplycost = (
select
min(ps_supplycost)
from partsupp, supplier, nation, region
where
p_partkey = ps_partkey
and s_suppkey = ps_suppkey
and s_nationkey = n_nationkey
and n_regionkey = r_regionkey
and r_name = 'AMERICA'
)
order by s_acctbal desc, n_name, s_name, p_partkey
LIMIT 100;
QUERY PLAN
----------------------------------------------------------------------------------------------------------
Limit
-> Sort
Sort Key: supplier.s_acctbal DESC, nation.n_name, supplier.s_name, part.p_partkey
-> Merge Join
Merge Cond: (part.p_partkey = partsupp.ps_partkey)
Join Filter: (partsupp.ps_supplycost = (SubPlan 1))
-> Gather Merge
Workers Planned: 4
-> Parallel Index Scan using <strong>part_pkey</strong> on part
Filter: (((p_type)::text ~~ '%BRASS'::text) AND (p_size = 36))
-> Materialize
-> Sort
Sort Key: partsupp.ps_partkey
-> Nested Loop
-> Nested Loop
Join Filter: (nation.n_regionkey = region.r_regionkey)
-> Seq Scan on region
Filter: (r_name = 'AMERICA'::bpchar)
-> Hash Join
Hash Cond: (supplier.s_nationkey = nation.n_nationkey)
-> Seq Scan on supplier
-> Hash
-> Seq Scan on nation
-> Index Scan using idx_partsupp_suppkey on partsupp
Index Cond: (ps_suppkey = supplier.s_suppkey)
SubPlan 1
-> Aggregate
-> Nested Loop
Join Filter: (nation_1.n_regionkey = region_1.r_regionkey)
-> Seq Scan on region region_1
Filter: (r_name = 'AMERICA'::bpchar)
-> Nested Loop
-> Nested Loop
-> Index Scan using idx_partsupp_partkey on partsupp partsupp_1
Index Cond: (part.p_partkey = ps_partkey)
-> Index Scan using supplier_pkey on supplier supplier_1
Index Cond: (s_suppkey = partsupp_1.ps_suppkey)
-> Index Scan using nation_pkey on nation nation_1
Index Cond: (n_nationkey = supplier_1.s_nationkey)
"Merge Join" ๋
ธ๋๋ "Gather Merge" ์์ ์์นํฉ๋๋ค. ๋ฐ๋ผ์ ๋ณํฉ์์๋ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ "Parallel Index Scan" ๋
ธ๋๋ ์ฌ์ ํ ์ธ๊ทธ๋จผํธ์ ๋์์ด ๋ฉ๋๋ค. part_pkey
.
๊ตฌ๊ฐ๋ณ ์ฐ๊ฒฐ
PostgreSQL 11์์
tpch=# set enable_partitionwise_join=t;
tpch=# explain (costs off) select * from prt1 t1, prt2 t2
where t1.a = t2.b and t1.b = 0 and t2.b between 0 and 10000;
QUERY PLAN
---------------------------------------------------
Append
-> Hash Join
Hash Cond: (t2.b = t1.a)
-> Seq Scan on prt2_p1 t2
Filter: ((b >= 0) AND (b <= 10000))
-> Hash
-> Seq Scan on prt1_p1 t1
Filter: (b = 0)
-> Hash Join
Hash Cond: (t2_1.b = t1_1.a)
-> Seq Scan on prt2_p2 t2_1
Filter: ((b >= 0) AND (b <= 10000))
-> Hash
-> Seq Scan on prt1_p2 t1_1
Filter: (b = 0)
tpch=# set parallel_setup_cost = 1;
tpch=# set parallel_tuple_cost = 0.01;
tpch=# explain (costs off) select * from prt1 t1, prt2 t2
where t1.a = t2.b and t1.b = 0 and t2.b between 0 and 10000;
QUERY PLAN
-----------------------------------------------------------
Gather
Workers Planned: 4
-> Parallel Append
-> Parallel Hash Join
Hash Cond: (t2_1.b = t1_1.a)
-> Parallel Seq Scan on prt2_p2 t2_1
Filter: ((b >= 0) AND (b <= 10000))
-> Parallel Hash
-> Parallel Seq Scan on prt1_p2 t1_1
Filter: (b = 0)
-> Parallel Hash Join
Hash Cond: (t2.b = t1.a)
-> Parallel Seq Scan on prt2_p1 t2
Filter: ((b >= 0) AND (b <= 10000))
-> Parallel Hash
-> Parallel Seq Scan on prt1_p1 t1
Filter: (b = 0)
๊ฐ์ฅ ์ค์ํ ๊ฒ์ ์น์ ์ ์ฐ๊ฒฐ์ด ํด๋น ์น์ ์ด ์ถฉ๋ถํ ํฐ ๊ฒฝ์ฐ์๋ง ํํํ๋ค๋ ๊ฒ์ ๋๋ค.
๋ณ๋ ฌ ์ถ๊ฐ
์ฌ๊ธฐ์๋ 2๊ฐ์ ์์ ์ ํ๋ก์ธ์ค๊ฐ ์คํ ์ค์ด์ง๋ง 4๊ฐ๊ฐ ํ์ฑํ๋์ด ์์ต๋๋ค.
tpch=# explain (costs off) select sum(l_quantity) as sum_qty from lineitem where l_shipdate <= date '1998-12-01' - interval '105' day union all select sum(l_quantity) as sum_qty from lineitem where l_shipdate <= date '2000-12-01' - interval '105' day;
QUERY PLAN
------------------------------------------------------------------------------------------------
Gather
Workers Planned: 2
-> Parallel Append
-> Aggregate
-> Seq Scan on lineitem
Filter: (l_shipdate <= '2000-08-18 00:00:00'::timestamp without time zone)
-> Aggregate
-> Seq Scan on lineitem lineitem_1
Filter: (l_shipdate <= '1998-08-18 00:00:00'::timestamp without time zone)
๊ฐ์ฅ ์ค์ํ ๋ณ์
- WORK_MEM์ ์ฟผ๋ฆฌ๋ฟ๋ง ์๋๋ผ ํ๋ก์ธ์ค๋น ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ํํฉ๋๋ค. ํ๋ก์ธ์ค๋ค ์ฐ๊ฒฐ = ๋ง์ ๋ฉ๋ชจ๋ฆฌ.
โ ์คํ ํ๋ก๊ทธ๋จ์ด ๊ณํ์ ๋ณ๋ ฌ ์ฒ๋ฆฌ์ ์ฌ์ฉํ ์์ ์ ํ๋ก์ธ์ค ์.max_parallel_workers_per_gather
โ ์ด ์์ ์ ํ๋ก์ธ์ค ์๋ฅผ ์๋ฒ์ CPU ์ฝ์ด ์์ ๋ง๊ฒ ์กฐ์ ํฉ๋๋ค.max_worker_processes
- ๋์ผํ์ง๋ง ๋ณ๋ ฌ ์์ ํ๋ก์ธ์ค์ ๊ฒฝ์ฐ์ ๋๋ค.max_parallel_workers
๊ฒฐ๊ณผ
๋ฒ์ 9.6๋ถํฐ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ ๋ง์ ํ์ด๋ ์ธ๋ฑ์ค๋ฅผ ๊ฒ์ํ๋ ๋ณต์กํ ์ฟผ๋ฆฌ์ ์ฑ๋ฅ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค. PostgreSQL 10์์๋ ๋ณ๋ ฌ ์ฒ๋ฆฌ๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ฑํ๋์ด ์์ต๋๋ค. OLTP ์์ ๋์ด ๋ง์ ์๋ฒ์์๋ ์ด๋ฅผ ๋นํ์ฑํํ๋ ๊ฒ์ ์์ง ๋ง์ญ์์ค. ์์ฐจ ์ค์บ์ด๋ ์ธ๋ฑ์ค ์ค์บ์ ๋ง์ ๋ฆฌ์์ค๋ฅผ ์๋ชจํฉ๋๋ค. ์ ์ฒด ๋ฐ์ดํฐ ์ธํธ์ ๋ํ ๋ณด๊ณ ์๋ฅผ ์คํํ์ง ์๋ ๊ฒฝ์ฐ ๋๋ฝ๋ ์ธ๋ฑ์ค๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ ์ ์ ํ ๋ถํ ์ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์์ต๋๋ค.
์ฐธ์กฐ
https://www.postgresql.org/docs/11/how-parallel-query-works.html https://www.postgresql.org/docs/11/parallel-plans.html http://ashutoshpg.blogspot.com/2017/12/partition-wise-joins-divide-and-conquer.html http://rhaas.blogspot.com/2016/04/postgresql-96-with-parallel-query-vs.html http://amitkapila16.blogspot.com/2015/11/parallel-sequential-scans-in-play.html https://write-skew.blogspot.com/2018/01/parallel-hash-for-postgresql.html http://rhaas.blogspot.com/2017/03/parallel-query-v2.html https://blog.2ndquadrant.com/parallel-monster-benchmark/ https://blog.2ndquadrant.com/parallel-aggregate/ https://www.depesz.com/2018/02/12/waiting-for-postgresql-11-support-parallel-btree-index-builds/ PostgreSQL 11์ ๋ณ๋ ฌ์ฑ
์ถ์ฒ : habr.com