PostgreSQL์˜ ๋ณ‘๋ ฌ ์ฟผ๋ฆฌ

PostgreSQL์˜ ๋ณ‘๋ ฌ ์ฟผ๋ฆฌ
์ตœ์‹  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 ๋ฒค์น˜๋งˆํฌ ์ฟผ๋ฆฌ์˜ ์‘๋‹ต ์‹œ๊ฐ„์„ ์ค„์ด๋ ค๊ณ  ๋…ธ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฒค์น˜๋งˆํฌ๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  PostgreSQL์— ์ ์‘. ์ด๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋‚˜ ํ•˜๋“œ์›จ์–ด ๋น„๊ต๋ฅผ ์œ„ํ•œ ๊ฒƒ์ด ์•„๋‹Œ TPC-H ๋ฒค์น˜๋งˆํฌ์˜ ๋น„๊ณต์‹์  ์‚ฌ์šฉ์ž…๋‹ˆ๋‹ค.

  1. TPC-H_Tools_v2.17.3.zip(๋˜๋Š” ์ตœ์‹  ๋ฒ„์ „) ๋‹ค์šด๋กœ๋“œ TPC ์˜คํ”„์‚ฌ์ดํŠธ์—์„œ.
  2. makefile.suite์˜ ์ด๋ฆ„์„ Makefile๋กœ ๋ฐ”๊พธ๊ณ  ์—ฌ๊ธฐ์— ์„ค๋ช…๋œ ๋Œ€๋กœ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค. https://github.com/tvondra/pg_tpch . make ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ์ปดํŒŒ์ผํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฐ์ดํ„ฐ ์ƒ์„ฑ: ./dbgen -s 10 23GB ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ณ‘๋ ฌ ์ฟผ๋ฆฌ์™€ ๋น„๋ณ‘๋ ฌ ์ฟผ๋ฆฌ์˜ ์„ฑ๋Šฅ ์ฐจ์ด๋ฅผ ํ™•์ธํ•˜๊ธฐ์— ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.
  4. ํŒŒ์ผ ๋ณ€ํ™˜ tbl ะฒ csv ั for ะธ sed.
  5. ์ €์žฅ์†Œ ๋ณต์ œ pg_tpch ๊ทธ๋ฆฌ๊ณ  ํŒŒ์ผ์„ ๋ณต์‚ฌํ•˜์„ธ์š” csv ะฒ pg_tpch/dss/data.
  6. ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฟผ๋ฆฌ ๋งŒ๋“ค๊ธฐ qgen.
  7. ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. ./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)๋ฐฐ.

์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ?

ํ”„๋กœ์„ธ์Šค

์š”์ฒญ ์‹คํ–‰์€ ํ•ญ์ƒ ์„ ํ–‰ ํ”„๋กœ์„ธ์Šค์—์„œ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค. ๋ฆฌ๋”๋Š” ๋ชจ๋“  ๋น„๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์™€ ์ผ๋ถ€ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ž‘์—…์ž ํ”„๋กœ์„ธ์Šค๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋Š” ์ธํ”„๋ผ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋™์  ๋ฐฐ๊ฒฝ ์ž‘์—…์ž ํ”„๋กœ์„ธ์Šค (๋ฒ„์ „ 9.4๋ถ€ํ„ฐ). PostgreSQL์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„์€ ์Šค๋ ˆ๋“œ๊ฐ€ ์•„๋‹Œ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ 3๊ฐœ์˜ ์ž‘์—…์ž ํ”„๋กœ์„ธ์Šค๊ฐ€ ์žˆ๋Š” ์ฟผ๋ฆฌ๋Š” ๊ธฐ์กด ์ฒ˜๋ฆฌ๋ณด๋‹ค 4๋ฐฐ ๋” ๋น ๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒํ˜ธ ์ž‘์šฉ

์ž‘์—…์ž ํ”„๋กœ์„ธ์Šค๋Š” ๋ฉ”์‹œ์ง€ ๋Œ€๊ธฐ์—ด(๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ๊ธฐ๋ฐ˜)์„ ํ†ตํ•ด ๋ฆฌ๋”์™€ ํ†ต์‹ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ํ”„๋กœ์„ธ์Šค์—๋Š” ์˜ค๋ฅ˜์šฉ ๋Œ€๊ธฐ์—ด๊ณผ ํŠœํ”Œ์šฉ ๋Œ€๊ธฐ์—ด์ด 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์—์„œ ๊ตฌ๊ฐ„๋ณ„ ์—ฐ๊ฒฐ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์Šค์ผ€์ค„๋ง ๋น„์šฉ์ด ๋งค์šฐ ๋†’์Šต๋‹ˆ๋‹ค. ์œ ์‚ฌํ•œ ํŒŒํ‹ฐ์…”๋‹์„ ๊ฐ€์ง„ ํ…Œ์ด๋ธ”์€ ํŒŒํ‹ฐ์…˜๋ณ„๋กœ ์กฐ์ธ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์‹์œผ๋กœ Postgres๋Š” ๋” ์ž‘์€ ํ•ด์‹œ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ์„น์…˜์˜ ์—ฐ๊ฒฐ์€ ํ‰ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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)

๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒƒ์€ ์„น์…˜์˜ ์—ฐ๊ฒฐ์ด ํ•ด๋‹น ์„น์…˜์ด ์ถฉ๋ถ„ํžˆ ํฐ ๊ฒฝ์šฐ์—๋งŒ ํ‰ํ–‰ํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ณ‘๋ ฌ ์ถ”๊ฐ€

๋ณ‘๋ ฌ ์ถ”๊ฐ€ ๋‹ค์–‘ํ•œ ์›Œํฌํ”Œ๋กœ์˜ ๋‹ค์–‘ํ•œ ๋ธ”๋ก ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ UNION ALL ์ฟผ๋ฆฌ์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ ์€ ๊ฐ ์ž‘์—…์ž ํ”„๋กœ์„ธ์Šค๊ฐ€ 1๊ฐœ์˜ ์š”์ฒญ๋งŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณ‘๋ ฌ์„ฑ์ด ๋‚ฎ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” 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 โ€” ์‹คํ–‰ ํ”„๋กœ๊ทธ๋žจ์ด ๊ณ„ํš์˜ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์— ์‚ฌ์šฉํ•  ์ž‘์—…์ž ํ”„๋กœ์„ธ์Šค ์ˆ˜.
  • max_worker_processes โ€” ์ด ์ž‘์—…์ž ํ”„๋กœ์„ธ์Šค ์ˆ˜๋ฅผ ์„œ๋ฒ„์˜ CPU ์ฝ”์–ด ์ˆ˜์— ๋งž๊ฒŒ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
  • max_parallel_workers - ๋™์ผํ•˜์ง€๋งŒ ๋ณ‘๋ ฌ ์ž‘์—… ํ”„๋กœ์„ธ์Šค์˜ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ

๋ฒ„์ „ 9.6๋ถ€ํ„ฐ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋Š” ๋งŽ์€ ํ–‰์ด๋‚˜ ์ธ๋ฑ์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ณต์žกํ•œ ์ฟผ๋ฆฌ์˜ ์„ฑ๋Šฅ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. PostgreSQL 10์—์„œ๋Š” ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. OLTP ์ž‘์—…๋Ÿ‰์ด ๋งŽ์€ ์„œ๋ฒ„์—์„œ๋Š” ์ด๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์ˆœ์ฐจ ์Šค์บ”์ด๋‚˜ ์ธ๋ฑ์Šค ์Šค์บ”์€ ๋งŽ์€ ๋ฆฌ์†Œ์Šค๋ฅผ ์†Œ๋ชจํ•ฉ๋‹ˆ๋‹ค. ์ „์ฒด ๋ฐ์ดํ„ฐ ์„ธํŠธ์— ๋Œ€ํ•œ ๋ณด๊ณ ์„œ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๋ˆ„๋ฝ๋œ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ ์ ˆํ•œ ๋ถ„ํ• ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ์กฐ

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€