๐Ÿš€ PostgreSQL์—์„œ ์ง€์—ฐ ์ฟผ๋ฆฌ์™€ ๊ณตํ†ต ์ฟผ๋ฆฌ์˜ ์ดํ•ดโ€• ์„ฑ๋Šฅ๊นŒ์ง€ ๊ณ ๋ คํ•œ ๊ณตํ†ต ์ฟผ๋ฆฌ ์„ค๊ณ„์˜ ์ค‘์š”์„ฑ

๐Ÿงฉ 1. ์ง€์—ฐ ์ฟผ๋ฆฌ(Delayed Query)๋ž€?

PostgreSQL์—์„œ ์ง€์—ฐ ์ฟผ๋ฆฌ๋ž€ ์ผ๋ฐ˜์ ์œผ๋กœ ์ฟผ๋ฆฌ ์‹คํ–‰์ด ์ฆ‰์‹œ ์ˆ˜ํ–‰๋˜์ง€ ์•Š๊ณ , ๊ฒฐ๊ณผ๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์‹ค์ œ ์‹คํ–‰์ด ์ด๋ค„์ง€๋Š” ํ˜•ํƒœ๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค.
์ฆ‰, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—”์ง„์ด ๊ฐ€๋Šฅํ•œ ํ•œ Lazy Execution(์ง€์—ฐ ์‹คํ–‰) ์ „๋žต์„ ์‚ฌ์šฉํ•ด ๋ถˆํ•„์š”ํ•œ ์—ฐ์‚ฐ์„ ์ค„์ด๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

๋Œ€ํ‘œ์ ์ธ ์˜ˆ์‹œ๋Š” ๋ทฐ(View) ๋˜๋Š” CTE(Common Table Expression) ์ž…๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, ์•„๋ž˜ ์ฟผ๋ฆฌ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

WITH user_data AS (
  SELECT * FROM users WHERE is_active = true
)
SELECT * FROM user_data WHERE age > 30;

์ด๋•Œ PostgreSQL์€ user_data๋ฅผ ์‹ค์ œ ํ…Œ์ด๋ธ”์ฒ˜๋Ÿผ ์ฆ‰์‹œ ์ƒ์„ฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋Œ€์‹  ์ตœ์ข… SELECT๊ฐ€ ์‹คํ–‰๋  ๋•Œ๊นŒ์ง€ ๋‚ด๋ถ€์ ์œผ๋กœ ์ง€์—ฐ์‹œ์ผœ, ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ์‹คํ–‰ํ•˜๋„๋ก ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์ด ๋ฐ”๋กœ ์ง€์—ฐ ์ฟผ๋ฆฌ์˜ ํ•ต์‹ฌ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค โ€” “ํ•„์š”ํ•  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.”

โš™๏ธ ์ง€์—ฐ ์ฟผ๋ฆฌ์˜ ์žฅ์ 

  • ๋ถˆํ•„์š”ํ•œ I/O๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Œ
  • ์กฐ์ธ๊ณผ ํ•„ํ„ฐ ์กฐ๊ฑด์ด ํ•ฉ์ณ์ ธ ์‹คํ–‰ ๊ณ„ํš์ด ๋” ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ์Œ
  • ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๊ฐ์†Œ

โš ๏ธ ๋‹จ์ 

  • ๋ณต์žกํ•œ ์„œ๋ธŒ์ฟผ๋ฆฌ ๊ตฌ์กฐ์—์„œ๋Š” ์‹คํ–‰ ๊ณ„ํš์ด ์˜ˆ์ธกํ•˜๊ธฐ ์–ด๋ ค์›€
  • ์ค‘๋ณต ์—ฐ์‚ฐ์ด ๋งŽ์•„์งˆ ๊ฒฝ์šฐ, ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์„ฑ๋Šฅ ์ €ํ•˜ ๊ฐ€๋Šฅ

๐Ÿงฑ 2. ๊ณตํ†ต ์ฟผ๋ฆฌ(Common Query)๋ž€?

๊ณตํ†ต ์ฟผ๋ฆฌ๋Š” ๊ฐœ๋ฐœ ์‹œ ์—ฌ๋Ÿฌ ์„œ๋น„์Šค๋‚˜ ๋ชจ๋“ˆ์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ฟผ๋ฆฌ ๋กœ์ง์„ ๋ณ„๋„๋กœ ์ •์˜ํ•œ ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๋Š” ๊ณตํ†ต ์ฟผ๋ฆฌ๋ฅผ ์•„๋ž˜์ฒ˜๋Ÿผ ํ•˜๋‚˜์˜ SQL ํ•จ์ˆ˜๋‚˜ View๋กœ ๋งŒ๋“ค์–ด๋‘๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

CREATE VIEW active_user_info AS
SELECT id, name, email
FROM users
WHERE is_active = true;

์ด์ œ ๋ชจ๋“  ์„œ๋น„์Šค์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•˜๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

SELECT * FROM active_user_info WHERE age > 30;

์ด์ฒ˜๋Ÿผ ์ฝ”๋“œ ์ค‘๋ณต์„ ์ค„์ด๊ณ , ๋กœ์ง ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ์ ์ด ๊ณตํ†ต ์ฟผ๋ฆฌ์˜ ํฐ ์žฅ์ ์ž…๋‹ˆ๋‹ค.


โšก 3. ํ•˜์ง€๋งŒโ€ฆ ๊ณตํ†ต ์ฟผ๋ฆฌ๋Š” ์„ฑ๋Šฅ์„ ๋ฐ˜๋“œ์‹œ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค

๋งŽ์€ ๊ฐœ๋ฐœ์ž๊ฐ€ โ€œ๊ณตํ†ต ์ฟผ๋ฆฌ = ํšจ์œจ์ ์ธ ์ฝ”๋“œโ€ ๋ผ๊ณ  ์ฐฉ๊ฐํ•˜์ง€๋งŒ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ๋Š” ์ƒํ™ฉ์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค.
๊ณตํ†ต ์ฟผ๋ฆฌ๋ฅผ ์ž˜๋ชป ์„ค๊ณ„ํ•˜๋ฉด ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์ด ์‹ฌ๊ฐํ•˜๊ฒŒ ์ €ํ•˜๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿง  ์˜ˆ๋ฅผ ๋“ค์–ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

CREATE VIEW common_order_data AS
SELECT
  o.id,
  o.user_id,
  u.name,
  o.total_price,
  o.created_at
FROM orders o
JOIN users u ON u.id = o.user_id;

์ด ์ฟผ๋ฆฌ๋ฅผ ์—ฌ๋Ÿฌ ์„œ๋น„์Šค์—์„œ ์žฌ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ด…์‹œ๋‹ค.
ํ•˜์ง€๋งŒ ์ผ๋ถ€ ์„œ๋น„์Šค์—์„œ๋Š” user_id๋งŒ ํ•„์š”ํ•˜๊ณ , ๋‹ค๋ฅธ ์„œ๋น„์Šค๋Š” created_at์œผ๋กœ ์ •๋ ฌ๋งŒ ํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ PostgreSQL์€ ๋งค๋ฒˆ ์ „์ฒด JOIN์„ ๋‹ค์‹œ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋˜๋ฉฐ,
์‹ค์ œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ณด๋‹ค ํ›จ์”ฌ ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ  ์ •๋ ฌํ•˜๋Š” ๋น„ํšจ์œจ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, ๊ณตํ†ต ์ฟผ๋ฆฌ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์€ ๋†’์ง€๋งŒ, ์‹คํ–‰ ๊ณ„ํš์€ ๋น„ํšจ์œจ์ ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿงญ 4. ๊ณตํ†ต ์ฟผ๋ฆฌ๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ ๊ณ ๋ คํ•ด์•ผ ํ•  ์‚ฌํ•ญ

ํ•ญ๋ชฉ์„ค๋ช…์˜ˆ์‹œ
์‹คํ–‰ ๊ณ„ํš (EXPLAIN ๋ถ„์„)๊ณตํ†ต ์ฟผ๋ฆฌ ์‹คํ–‰ ์‹œ ์‹ค์ œ ๋น„์šฉ์„ ๋ฐ˜๋“œ์‹œ ํ™•์ธํ•ด์•ผ ํ•จEXPLAIN ANALYZE SELECT * FROM common_order_data;
ํ•„์š”ํ•œ ์ปฌ๋Ÿผ๋งŒ SELECT์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ปฌ๋Ÿผ๊นŒ์ง€ ์กฐํšŒํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ I/O ๋ฐœ์ƒSELECT id, name ๋งŒ ํ•„์š”ํ•˜๋‹ค๋ฉด ๊ทธ๊ฒƒ๋งŒ ์กฐํšŒ
์กฐ๊ฑด์„ ์™ธ๋ถ€์—์„œ ๋ฐ›๋„๋ก ์„ค๊ณ„๊ณตํ†ต ์ฟผ๋ฆฌ ๋‚ด๋ถ€์—์„œ WHERE ์กฐ๊ฑด์„ ๊ณ ์ •ํ•˜์ง€ ๋ง ๊ฒƒWHERE is_active = :is_active
์ธ๋ฑ์Šค ๊ณ ๋ ค๊ณตํ†ต ์ฟผ๋ฆฌ ๋Œ€์ƒ ์ปฌ๋Ÿผ์— ์ ์ ˆํ•œ ์ธ๋ฑ์Šค ์ƒ์„ฑCREATE INDEX idx_users_is_active ON users(is_active);
์บ์‹œ ํ™œ์šฉ์ž์ฃผ ์กฐํšŒ๋˜๋Š” ๊ณตํ†ต ์ฟผ๋ฆฌ๋Š” Redis ๋“ฑ ์บ์‹œ ์‚ฌ์šฉ ๊ฒ€ํ† ์‹ค์‹œ๊ฐ„์„ฑ์ด ๋‚ฎ์€ ๋ฐ์ดํ„ฐ๋ผ๋ฉด ์บ์‹ฑ ๊ณ ๋ ค

๐Ÿงฉ 5. ๋งˆ๋ฌด๋ฆฌ โ€” ์žฌ์‚ฌ์šฉ๋ณด๋‹ค ์ค‘์š”ํ•œ ๊ฑด โ€œ์‹คํ–‰ ํšจ์œจ์„ฑโ€

PostgreSQL์—์„œ ๊ณตํ†ต ์ฟผ๋ฆฌ๋Š” ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ์ผ๊ด€์„ฑ ์ธก๋ฉด์—์„œ๋Š” ๋งค์šฐ ์œ ์šฉํ•˜์ง€๋งŒ,
๋ชจ๋“  ์ƒํ™ฉ์— ์ ํ•ฉํ•œ ์ •๋‹ต์€ ์•„๋‹™๋‹ˆ๋‹ค.

ํŠนํžˆ ๋Œ€๊ทœ๋ชจ ํŠธ๋ž˜ํ”ฝ์ด๋‚˜ ๋ณต์žกํ•œ ์กฐ์ธ ํ™˜๊ฒฝ์—์„œ๋Š”

โ€œ๊ณตํ†ต ์ฟผ๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋ผ, ์„œ๋น„์Šค๋ณ„ ์ตœ์ ํ™” ์ฟผ๋ฆฌโ€๊ฐ€ ๋” ์ข‹์€ ์„ ํƒ์ด ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

โœ… ํ•ต์‹ฌ ์š”์•ฝ

  • ์ง€์—ฐ ์ฟผ๋ฆฌ๋Š” ์‹คํ–‰ ํšจ์œจ์„ ๋†’์ด๋Š” PostgreSQL์˜ ๋‚ด๋ถ€ ์ „๋žต์ด๋‹ค.
  • ๊ณตํ†ต ์ฟผ๋ฆฌ๋Š” ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด์ง€๋งŒ, ์„ฑ๋Šฅ ๋ถ€ํ•˜๋ฅผ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ณตํ†ต ์ฟผ๋ฆฌ๋Š” ๋ฐ˜๋“œ์‹œ EXPLAIN ANALYZE๋กœ ์‹คํ–‰ ๊ณ„ํš์„ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค.

โœ๏ธ ๊ฒฐ๋ก 

๊ณตํ†ต ์ฟผ๋ฆฌ๋Š” ๊ฐœ๋ฐœ์˜ ํŽธ๋ฆฌํ•จ์„ ์ฃผ์ง€๋งŒ,
โ€œ์„ฑ๋Šฅ์„ ๋ชจ๋ฅด๋Š” ๊ณตํ†ต ์ฟผ๋ฆฌโ€๋Š” ์˜คํžˆ๋ ค ๋…์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

PostgreSQL์˜ ์‹คํ–‰ ๊ณ„ํš์„ ์ดํ•ดํ•˜๊ณ ,
๊ณตํ†ต ์ฟผ๋ฆฌ๋ฅผ โ€œํ•จ๊ป˜ ์“ฐ๋˜, ์ƒํ™ฉ์— ๋งž๊ฒŒ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐ์„ฑโ€์„ ๊ฐ€์ง€๋Š” ๊ฒƒ์ด
์ง„์ •ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ตœ์ ํ™”์˜ ์‹œ์ž‘์ž…๋‹ˆ๋‹ค.

Posted in

๋Œ“๊ธ€ ๋‚จ๊ธฐ๊ธฐ