PostgreSQL์—์„œ ์ธ๋ฑ์Šค์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ ์‚ฌ์šฉ

PostgreSQL์—์„œ ์ธ๋ฑ์Šค์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ ์‚ฌ์šฉ
Postgres ์„ธ๊ณ„์—์„œ ์ธ๋ฑ์Šค๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ €์žฅ์†Œ("ํž™"์ด๋ผ๊ณ  ํ•จ)๋ฅผ ํšจ์œจ์ ์œผ๋กœ ํƒ์ƒ‰ํ•˜๋Š” ๋ฐ ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค. Postgres๋Š” ํด๋Ÿฌ์Šคํ„ฐ๋ง์„ ์ง€์›ํ•˜์ง€ ์•Š์œผ๋ฉฐ MVCC ์•„ํ‚คํ…์ฒ˜๋กœ ์ธํ•ด ๋™์ผํ•œ ํŠœํ”Œ์˜ ์—ฌ๋Ÿฌ ๋ฒ„์ „์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ํšจ์œจ์ ์ธ ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์œ ์ง€ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ์ธ๋ฑ์Šค ์‚ฌ์šฉ์„ ์ตœ์ ํ™”ํ•˜๊ณ  ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ํŒ์ž…๋‹ˆ๋‹ค.

์ฐธ๊ณ : ์•„๋ž˜ ํ‘œ์‹œ๋œ ์ฟผ๋ฆฌ๋Š” ์ˆ˜์ •๋˜์ง€ ์•Š์€ ํŒŒ๊ธธ๋ผ ์ƒ˜ํ”Œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค.

์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค ์‚ฌ์šฉ

๋น„ํ™œ์„ฑ ์‚ฌ์šฉ์ž์˜ ์ด๋ฉ”์ผ ์ฃผ์†Œ ์ถ”์ถœ ์š”์ฒญ์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ…Œ์ด๋ธ” customer ์นผ๋Ÿผ์ด ์žˆ๋‹ค active, ์ฟผ๋ฆฌ๋Š” ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

pagila=# EXPLAIN SELECT email FROM customer WHERE active=0;
                        QUERY PLAN
-----------------------------------------------------------
 Seq Scan on customer  (cost=0.00..16.49 rows=15 width=32)
   Filter: (active = 0)
(2 rows)

์ฟผ๋ฆฌ๋Š” ์ „์ฒด ํ…Œ์ด๋ธ” ์Šค์บ” ์‹œํ€€์Šค๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. customer. ์—ด์— ์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋ด…์‹œ๋‹ค active:

pagila=# CREATE INDEX idx_cust1 ON customer(active);
CREATE INDEX
pagila=# EXPLAIN SELECT email FROM customer WHERE active=0;
                                 QUERY PLAN
-----------------------------------------------------------------------------
 Index Scan using idx_cust1 on customer  (cost=0.28..12.29 rows=15 width=32)
   Index Cond: (active = 0)
(2 rows)

๋„์›€์ด ๋˜์—ˆ๊ณ  ํ›„์† ์Šค์บ”์€ "index scan". ์ด๋Š” Postgres๊ฐ€ "idx_cust1"๋ผ๊ณ  ๋งํ•œ ๋‹ค์Œ ํ…Œ์ด๋ธ” ํž™์„ ๊ณ„์† ๊ฒ€์ƒ‰ํ•˜์—ฌ ๋‹ค๋ฅธ ์—ด์˜ ๊ฐ’์„ ์ฝ์Šต๋‹ˆ๋‹ค(์ด ๊ฒฝ์šฐ ์—ด email) ์ฟผ๋ฆฌ์— ํ•„์š”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํฌ๊ด„ ์ธ๋ฑ์Šค๋Š” PostgreSQL 11์— ๋„์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ธ๋ฑ์Šค ์ž์ฒด์— ํ•˜๋‚˜ ์ด์ƒ์˜ ์ถ”๊ฐ€ ์—ด์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ๊ฐ’์€ ์ธ๋ฑ์Šค ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๊ณ  ์ธ๋ฑ์Šค ๋‚ด๋ถ€์— ์ด๋ฉ”์ผ ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๋ฉด Postgres๋Š” ๊ฐ’์— ๋Œ€ํ•ด ํ…Œ์ด๋ธ” โ€‹โ€‹ํž™์„ ๊ฒ€์ƒ‰ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. email. ์ด๊ฒƒ์ด ์ž‘๋™ํ•˜๋Š”์ง€ ๋ด…์‹œ๋‹ค:

pagila=# CREATE INDEX idx_cust2 ON customer(active) INCLUDE (email);
CREATE INDEX
pagila=# EXPLAIN SELECT email FROM customer WHERE active=0;
                                    QUERY PLAN
----------------------------------------------------------------------------------
 Index Only Scan using idx_cust2 on customer  (cost=0.28..12.29 rows=15 width=32)
   Index Cond: (active = 0)
(2 rows)

ยซIndex Only Scan'๋Š” ์ด์ œ ์ฟผ๋ฆฌ์— ์ธ๋ฑ์Šค๋งŒ ํ•„์š”ํ•˜๋ฏ€๋กœ ํ…Œ์ด๋ธ” ํž™์„ ์ฝ๊ธฐ ์œ„ํ•œ ๋ชจ๋“  ๋””์Šคํฌ I/O๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋œ๋‹ค๊ณ  ์•Œ๋ ค์ค๋‹ˆ๋‹ค.

์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค๋Š” ํ˜„์žฌ B-ํŠธ๋ฆฌ์—๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๊ฒฝ์šฐ ์œ ์ง€ ๊ด€๋ฆฌ ๋…ธ๋ ฅ์ด ๋” ๋งŽ์ด ๋“ญ๋‹ˆ๋‹ค.

๋ถ€๋ถ„ ์ธ๋ฑ์Šค ์‚ฌ์šฉ

๋ถ€๋ถ„ ์ธ๋ฑ์Šค๋Š” ํ…Œ์ด๋ธ”์— ์žˆ๋Š” ํ–‰์˜ ํ•˜์œ„ ์ง‘ํ•ฉ๋งŒ ์ธ๋ฑ์‹ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ธ๋ฑ์Šค ํฌ๊ธฐ๊ฐ€ ์ ˆ์•ฝ๋˜๊ณ  ์Šค์บ” ์†๋„๊ฐ€ ๋นจ๋ผ์ง‘๋‹ˆ๋‹ค.

์บ˜๋ฆฌํฌ๋‹ˆ์•„์— ์žˆ๋Š” ๊ณ ๊ฐ์˜ ์ด๋ฉ”์ผ ์ฃผ์†Œ ๋ชฉ๋ก์„ ์–ป๊ณ  ์‹ถ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์š”์ฒญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

SELECT c.email FROM customer c
JOIN address a ON c.address_id = a.address_id
WHERE a.district = 'California';
which has a query plan that involves scanning both the tables that are joined:
pagila=# EXPLAIN SELECT c.email FROM customer c
pagila-# JOIN address a ON c.address_id = a.address_id
pagila-# WHERE a.district = 'California';
                              QUERY PLAN
----------------------------------------------------------------------
 Hash Join  (cost=15.65..32.22 rows=9 width=32)
   Hash Cond: (c.address_id = a.address_id)
   ->  Seq Scan on customer c  (cost=0.00..14.99 rows=599 width=34)
   ->  Hash  (cost=15.54..15.54 rows=9 width=4)
         ->  Seq Scan on address a  (cost=0.00..15.54 rows=9 width=4)
               Filter: (district = 'California'::text)
(6 rows)

์ผ๋ฐ˜ ์ธ๋ฑ์Šค๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ:

pagila=# CREATE INDEX idx_address1 ON address(district);
CREATE INDEX
pagila=# EXPLAIN SELECT c.email FROM customer c
pagila-# JOIN address a ON c.address_id = a.address_id
pagila-# WHERE a.district = 'California';
                                      QUERY PLAN
---------------------------------------------------------------------------------------
 Hash Join  (cost=12.98..29.55 rows=9 width=32)
   Hash Cond: (c.address_id = a.address_id)
   ->  Seq Scan on customer c  (cost=0.00..14.99 rows=599 width=34)
   ->  Hash  (cost=12.87..12.87 rows=9 width=4)
         ->  Bitmap Heap Scan on address a  (cost=4.34..12.87 rows=9 width=4)
               Recheck Cond: (district = 'California'::text)
               ->  Bitmap Index Scan on idx_address1  (cost=0.00..4.34 rows=9 width=0)
                     Index Cond: (district = 'California'::text)
(8 rows)

์Šค์บ” address ์ธ๋ฑ์Šค ์Šค์บ”์œผ๋กœ ๋Œ€์ฒด๋˜์—ˆ์Šต๋‹ˆ๋‹ค. idx_address1๊ทธ๋Ÿฐ ๋‹ค์Œ ํž™์„ ์Šค์บ”ํ–ˆ์Šต๋‹ˆ๋‹ค. address.

์ด๊ฒƒ์€ ๋นˆ๋ฒˆํ•œ ์ฟผ๋ฆฌ์ด๊ณ  ์ตœ์ ํ™”๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ถ€๋ถ„ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. โ€˜Californiaโ€™:

pagila=# CREATE INDEX idx_address2 ON address(address_id) WHERE district='California';
CREATE INDEX
pagila=# EXPLAIN SELECT c.email FROM customer c
pagila-# JOIN address a ON c.address_id = a.address_id
pagila-# WHERE a.district = 'California';
                                           QUERY PLAN
------------------------------------------------------------------------------------------------
 Hash Join  (cost=12.38..28.96 rows=9 width=32)
   Hash Cond: (c.address_id = a.address_id)
   ->  Seq Scan on customer c  (cost=0.00..14.99 rows=599 width=34)
   ->  Hash  (cost=12.27..12.27 rows=9 width=4)
         ->  Index Only Scan using idx_address2 on address a  (cost=0.14..12.27 rows=9 width=4)
(5 rows)

์ด์ œ ์ฟผ๋ฆฌ๋Š” ์ฝ๊ธฐ๋งŒ ํ•ฉ๋‹ˆ๋‹ค. idx_address2 ๊ทธ๋ฆฌ๊ณ  ํ…Œ์ด๋ธ”์„ ๋งŒ์ง€์ง€ ์•Š๋Š”๋‹ค address.

๋‹ค์ค‘ ๊ฐ’ ์ธ๋ฑ์Šค ์‚ฌ์šฉ

์ธ๋ฑ์‹ฑํ•  ์ผ๋ถ€ ์—ด์€ ์Šค์นผ๋ผ ๋ฐ์ดํ„ฐ ์œ ํ˜•์„ ํฌํ•จํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—ด ์œ ํ˜• jsonb, arrays ะธ tsvector ๋ณตํ•ฉ ๋˜๋Š” ๋‹ค์ค‘ ๊ฐ’์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์—ด์„ ์ธ๋ฑ์‹ฑํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์ผ๋ฐ˜์ ์œผ๋กœ ํ•ด๋‹น ์—ด์˜ ๋ชจ๋“  ๊ฐœ๋ณ„ ๊ฐ’์„ ๊ฒ€์ƒ‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์‹คํŒจํ•œ ํ…Œ์ดํฌ์˜ ์ปท์ด ํฌํ•จ๋œ ๋ชจ๋“  ์˜ํ™”์˜ ์ œ๋ชฉ์„ ์ฐพ์•„๋ด…์‹œ๋‹ค. ํ…Œ์ด๋ธ” film ๋ผ๋Š” ํ…์ŠคํŠธ ์—ด์ด ์žˆ์Šต๋‹ˆ๋‹ค. special_features. ์˜ํ™”์— ์ด "ํŠน์ˆ˜ ์†์„ฑ"์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์—ด์—๋Š” ์š”์†Œ๊ฐ€ ํ…์ŠคํŠธ ๋ฐฐ์—ด๋กœ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. Behind The Scenes. ์ด๋Ÿฌํ•œ ๋ชจ๋“  ์˜ํ™”๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ ค๋ฉด "Behind The Scenes"๊ฐ€ ํฌํ•จ๋œ ๋ชจ๋“  ํ–‰์„ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ๋ฐฐ์—ด ๊ฐ’ special_features:

SELECT title FROM film WHERE special_features @> '{"Behind The Scenes"}';

์ค‘์ฒฉ ์—ฐ์‚ฐ์ž @> ์˜ค๋ฅธ์ชฝ์ด ์™ผ์ชฝ์˜ ํ•˜์œ„ ์ง‘ํ•ฉ์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

์š”์ฒญ ๊ณ„ํš:

pagila=# EXPLAIN SELECT title FROM film
pagila-# WHERE special_features @> '{"Behind The Scenes"}';
                           QUERY PLAN
-----------------------------------------------------------------
 Seq Scan on film  (cost=0.00..67.50 rows=5 width=15)
   Filter: (special_features @> '{"Behind The Scenes"}'::text[])
(2 rows)

67์˜ ๋น„์šฉ์œผ๋กœ ์ „์ฒด ํž™ ์Šค์บ”์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜ B-ํŠธ๋ฆฌ ์ธ๋ฑ์Šค๊ฐ€ ๋„์›€์ด ๋˜๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

pagila=# CREATE INDEX idx_film1 ON film(special_features);
CREATE INDEX
pagila=# EXPLAIN SELECT title FROM film
pagila-# WHERE special_features @> '{"Behind The Scenes"}';
                           QUERY PLAN
-----------------------------------------------------------------
 Seq Scan on film  (cost=0.00..67.50 rows=5 width=15)
   Filter: (special_features @> '{"Behind The Scenes"}'::text[])
(2 rows)

์ง€์ˆ˜๋Š” ๊ณ ๋ ค์กฐ์ฐจ ํ•˜์ง€ ์•Š์•˜๋‹ค. B-ํŠธ๋ฆฌ ์ธ๋ฑ์Šค๋Š” ์ธ๋ฑ์‹ฑ๋œ ๊ฐ’์˜ ๊ฐœ๋ณ„ ์š”์†Œ ์กด์žฌ๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

GIN ์ธ๋ฑ์Šค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

pagila=# CREATE INDEX idx_film2 ON film USING GIN(special_features);
CREATE INDEX
pagila=# EXPLAIN SELECT title FROM film
pagila-# WHERE special_features @> '{"Behind The Scenes"}';
                                QUERY PLAN
---------------------------------------------------------------------------
 Bitmap Heap Scan on film  (cost=8.04..23.58 rows=5 width=15)
   Recheck Cond: (special_features @> '{"Behind The Scenes"}'::text[])
   ->  Bitmap Index Scan on idx_film2  (cost=0.00..8.04 rows=5 width=0)
         Index Cond: (special_features @> '{"Behind The Scenes"}'::text[])
(4 rows)

GIN ์ธ๋ฑ์Šค๋Š” ์ธ๋ฑ์‹ฑ๋œ ๋ณตํ•ฉ ๊ฐ’์— ๋Œ€ํ•œ ๋‹จ์ผ ๊ฐ’ ๋งคํ•‘์„ ์ง€์›ํ•˜๋ฏ€๋กœ ์ฟผ๋ฆฌ ๊ณ„ํš ๋น„์šฉ์ด ์ ˆ๋ฐ˜ ์ด์ƒ ๊ฐ์†Œํ•ฉ๋‹ˆ๋‹ค.

์ค‘๋ณต ์ธ๋ฑ์Šค ์ œ๊ฑฐ

์ธ๋ฑ์Šค๋Š” ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ˆ„์ ๋˜๋ฉฐ ๋•Œ๋กœ๋Š” ์ƒˆ ์ธ๋ฑ์Šค๊ฐ€ ์ด์ „ ์ธ๋ฑ์Šค ์ค‘ ํ•˜๋‚˜์™€ ๋™์ผํ•œ ์ •์˜๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์นดํƒˆ๋กœ๊ทธ ๋ทฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ธ๋ฑ์Šค์˜ SQL ์ •์˜๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. pg_indexes. ๋™์ผํ•œ ์ •์˜๋ฅผ ์‰ฝ๊ฒŒ ์ฐพ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

 SELECT array_agg(indexname) AS indexes, replace(indexdef, indexname, '') AS defn
    FROM pg_indexes
GROUP BY defn
  HAVING count(*) > 1;
And hereโ€™s the result when run on the stock pagila database:
pagila=#   SELECT array_agg(indexname) AS indexes, replace(indexdef, indexname, '') AS defn
pagila-#     FROM pg_indexes
pagila-# GROUP BY defn
pagila-#   HAVING count(*) > 1;
                                indexes                                 |                                defn
------------------------------------------------------------------------+------------------------------------------------------------------
 {payment_p2017_01_customer_id_idx,idx_fk_payment_p2017_01_customer_id} | CREATE INDEX  ON public.payment_p2017_01 USING btree (customer_id
 {payment_p2017_02_customer_id_idx,idx_fk_payment_p2017_02_customer_id} | CREATE INDEX  ON public.payment_p2017_02 USING btree (customer_id
 {payment_p2017_03_customer_id_idx,idx_fk_payment_p2017_03_customer_id} | CREATE INDEX  ON public.payment_p2017_03 USING btree (customer_id
 {idx_fk_payment_p2017_04_customer_id,payment_p2017_04_customer_id_idx} | CREATE INDEX  ON public.payment_p2017_04 USING btree (customer_id
 {payment_p2017_05_customer_id_idx,idx_fk_payment_p2017_05_customer_id} | CREATE INDEX  ON public.payment_p2017_05 USING btree (customer_id
 {idx_fk_payment_p2017_06_customer_id,payment_p2017_06_customer_id_idx} | CREATE INDEX  ON public.payment_p2017_06 USING btree (customer_id
(6 rows)

์ƒ์œ„ ์ง‘ํ•ฉ ์ธ๋ฑ์Šค

๋งŽ์€ ์ธ๋ฑ์Šค๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ทธ ์ค‘ ํ•˜๋‚˜๋Š” ๋‹ค๋ฅธ ์ธ๋ฑ์Šค๋ฅผ ์ธ๋ฑ์‹ฑํ•˜๋Š” ์—ด์˜ ์ƒ์œ„ ์ง‘ํ•ฉ์„ ์ธ๋ฑ์‹ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋ฐ”๋žŒ์งํ•  ์ˆ˜๋„ ์žˆ๊ณ  ๋ฐ”๋žŒ์งํ•˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒ์œ„ ์ง‘ํ•ฉ์€ ์ธ๋ฑ์Šค ์ „์šฉ ์Šค์บ”์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๋Š” ์ข‹์ง€๋งŒ ๋„ˆ๋ฌด ๋งŽ์€ ๊ณต๊ฐ„์„ ์ฐจ์ง€ํ•˜๊ฑฐ๋‚˜ ์ƒ์œ„ ์ง‘ํ•ฉ์ด ์ตœ์ ํ™”ํ•˜๋ ค๋Š” ์ฟผ๋ฆฌ๊ฐ€ ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ธ๋ฑ์Šค์˜ ์ •์˜๋ฅผ ์ž๋™ํ™”ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ์œผ๋กœ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. pg_index ํ…Œ์ด๋ธ”์—์„œ pg_catalog.

์‚ฌ์šฉ๋˜์ง€ ์•Š์€ ์ธ๋ฑ์Šค

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฐœ์ „ํ•จ์— ๋”ฐ๋ผ ์ด๋“ค์ด ์‚ฌ์šฉํ•˜๋Š” ์ฟผ๋ฆฌ๋„ ๋ฐœ์ „ํ•ฉ๋‹ˆ๋‹ค. ์ด์ „์— ์ถ”๊ฐ€๋œ ์ธ๋ฑ์Šค๋Š” ๋” ์ด์ƒ ์ฟผ๋ฆฌ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ธ๋ฑ์Šค๊ฐ€ ์Šค์บ”๋  ๋•Œ๋งˆ๋‹ค ํ†ต๊ณ„ ๊ด€๋ฆฌ์ž์— ์˜ํ•ด ํ‘œ์‹œ๋˜๊ณ  ์‹œ์Šคํ…œ ์นดํƒˆ๋กœ๊ทธ ๋ณด๊ธฐ์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. pg_stat_user_indexes ๊ฐ’์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค idx_scan, ๋ˆ„์  ์นด์šดํ„ฐ์ž…๋‹ˆ๋‹ค. ์ผ์ • ๊ธฐ๊ฐ„(์˜ˆ: ํ•œ ๋‹ฌ) ๋™์•ˆ ์ด ๊ฐ’์„ ์ถ”์ ํ•˜๋ฉด ์–ด๋–ค ์ธ๋ฑ์Šค๊ฐ€ ์‚ฌ์šฉ๋˜์ง€ ์•Š๊ณ  ์‚ญ์ œ๋  ์ˆ˜ ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ์ข‹์€ ์•„์ด๋””์–ด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ์Šคํ‚ค๋งˆ์— ์žˆ๋Š” ๋ชจ๋“  ์ธ๋ฑ์Šค์˜ ํ˜„์žฌ ์Šค์บ” ์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ฟผ๋ฆฌ์ž…๋‹ˆ๋‹ค. โ€˜publicโ€™:

SELECT relname, indexrelname, idx_scan
FROM   pg_catalog.pg_stat_user_indexes
WHERE  schemaname = 'public';
with output like this:
pagila=# SELECT relname, indexrelname, idx_scan
pagila-# FROM   pg_catalog.pg_stat_user_indexes
pagila-# WHERE  schemaname = 'public'
pagila-# LIMIT  10;
    relname    |    indexrelname    | idx_scan
---------------+--------------------+----------
 customer      | customer_pkey      |    32093
 actor         | actor_pkey         |     5462
 address       | address_pkey       |      660
 category      | category_pkey      |     1000
 city          | city_pkey          |      609
 country       | country_pkey       |      604
 film_actor    | film_actor_pkey    |        0
 film_category | film_category_pkey |        0
 film          | film_pkey          |    11043
 inventory     | inventory_pkey     |    16048
(10 rows)

๋” ์ ์€ ์ˆ˜์˜ ์ž ๊ธˆ์œผ๋กœ ์ธ๋ฑ์Šค ์žฌ๊ตฌ์ถ•

์˜ˆ๋ฅผ ๋“ค์–ด ์ธ๋ฑ์Šค๊ฐ€ ๋น„๋Œ€ํ•ด์ง€๋ฉด ์ธ๋ฑ์Šค๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์œผ๋ฉฐ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๋ฉด ์Šค์บ” ์†๋„๊ฐ€ ๋นจ๋ผ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ธ๋ฑ์Šค๊ฐ€ ์†์ƒ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ธ๋ฑ์Šค ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ์ธ๋ฑ์Šค๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ณ‘๋ ฌ ์ธ๋ฑ์Šค ์ƒ์„ฑ ํ™œ์„ฑํ™”

PostgreSQL 11์—์„œ๋Š” B-Tree ์ธ๋ฑ์Šค ์ƒ์„ฑ์ด ๋™์‹œ์— ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ์ƒ์„ฑ ํ”„๋กœ์„ธ์Šค์˜ ์†๋„๋ฅผ ๋†’์ด๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ๋ณ‘๋ ฌ ์ž‘์—…์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค์Œ ๊ตฌ์„ฑ ์˜ต์…˜์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

SET max_parallel_workers = 32;
SET max_parallel_maintenance_workers = 16;

๊ธฐ๋ณธ๊ฐ’์ด ๋„ˆ๋ฌด ์ž‘์Šต๋‹ˆ๋‹ค. ์ด์ƒ์ ์œผ๋กœ ์ด๋Ÿฌํ•œ ์ˆซ์ž๋Š” ํ”„๋กœ์„ธ์„œ ์ฝ”์–ด์˜ ์ˆ˜์™€ ํ•จ๊ป˜ ์ฆ๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋” ์ฝ์–ด๋ณด๊ธฐ ์„ ์  ์„œ๋ฅ˜ ๋น„์น˜.

๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ธ๋ฑ์Šค ์ƒ์„ฑ

์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์ƒ‰์ธ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. CONCURRENTLY ํŒ€ CREATE INDEX:

pagila=# CREATE INDEX CONCURRENTLY idx_address1 ON address(district);
CREATE INDEX

์ด ์ธ๋ฑ์Šค ์ƒ์„ฑ ์ ˆ์ฐจ๋Š” ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์ž ๊ธˆ์ด ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์“ฐ๊ธฐ ์ž‘์—…์„ ์ฐจ๋‹จํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์—์„œ ์ผ๋ฐ˜์ ์ธ ์ธ๋ฑ์Šค ์ƒ์„ฑ ์ ˆ์ฐจ์™€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์— ๋” ๋งŽ์€ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๊ณ  ๋” ๋งŽ์€ ์ž์›์„ ์†Œ๋น„ํ•ฉ๋‹ˆ๋‹ค.

Postgres๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํญ๋ฐœ์ ์œผ๋กœ ์„ฑ์žฅํ•˜๋Š” ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์ƒ‰์ธ ์ƒ์„ฑ์„ ์œ„ํ•œ ๋งŽ์€ ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด ํŒ์ด ์ฟผ๋ฆฌ ์†๋„๋ฅผ ๋†’์ด๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ™•์žฅ์„ ์ค€๋น„ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ถœ์ฒ˜ : habr.com

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