์‹คํ–‰๊ณ„ํš(EXPLAIN) ํ•œ ๋ฒˆ์— ์ฝ๊ธฐ

์‹คํ–‰๊ณ„ํš(EXPLAIN) ์ฝ๋Š” ๋ฒ• — MySQL·PostgreSQL·Oracle·SQL Server ํ•œ ๋ฒˆ์—. ์ถ”๊ฐ€ํ•œ ์ธ๋ฑ์Šค๊ฐ€ ์‹ค์ œ๋กœ ํƒ€๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ์‹คํ–‰๊ณ„ํš์„ ๋ด์•ผ ํ•œ๋‹ค. DB๋งˆ๋‹ค ๋ช…๋ น์–ด๋„ ์ถœ๋ ฅ๋„ ๋‹ค๋ฅด์ง€๋งŒ, ๊ฒฐ๊ตญ ๋ณด๋Š” ๊ฒƒ์€ ๋˜‘๊ฐ™๋‹ค. ๋„ค ๊ฐ€์ง€ ์ฃผ์š” DB์˜ ์‹คํ–‰๊ณ„ํš ํ™•์ธ๋ฒ•์„, ์‹ค์ œ ์ถœ๋ ฅ๊ณผ ํ•จ๊ป˜ ์ •๋ฆฌํ•œ๋‹ค.


๋“ค์–ด๊ฐ€๋ฉฐ

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์ „์— ๋ณด๋Š” ๊ฒƒ๋“ค ๊ธ€์—์„œ ์ธ๋ฑ์Šค๊ฐ€ ์™œ ๋น ๋ฅธ์ง€, ์–ธ์ œ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ๋‹ค๋ค˜๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํ•œ ๊ฐ€์ง€ ์งˆ๋ฌธ์ด ๋‚จ๋Š”๋‹ค. ์ถ”๊ฐ€ํ•œ ์ธ๋ฑ์Šค๊ฐ€ ์‹ค์ œ๋กœ ์“ฐ์ด๊ณ  ์žˆ์„๊นŒ?

์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋†“๊ณ ๋„ ์ฟผ๋ฆฌ๊ฐ€ ์—ฌ์ „ํžˆ ๋А๋ฆฐ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. ์ธ๋ฑ์Šค๊ฐ€ ์žˆ๋Š”๋ฐ ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ์•ˆ ์“ฐ๊ธฐ๋กœ ํ–ˆ๊ฑฐ๋‚˜, ์“ธ ์ˆ˜ ์—†๊ฒŒ ์ฟผ๋ฆฌ๊ฐ€ ์ž‘์„ฑ๋๊ฑฐ๋‚˜, ํ†ต๊ณ„๊ฐ€ ์–ด๊ธ‹๋‚˜ ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ํ’€์Šค์บ”์ด ๋” ์‹ธ๋‹ค๊ณ  ์˜คํŒํ•œ ๊ฒฝ์šฐ๋‹ค. ์ด๊ฑธ ๋ˆˆ์œผ๋กœ ํ™•์ธํ•˜๋Š” ๋„๊ตฌ๊ฐ€ ์‹คํ–‰๊ณ„ํš(execution plan)์ด๋‹ค.

์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฑด ์‹œ์ž‘์ผ ๋ฟ์ด๋‹ค. ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ๊ทธ ์ธ๋ฑ์Šค๋ฅผ ์‹ค์ œ๋กœ ๊ณจ๋ž๋Š”์ง€๊นŒ์ง€ ์‹คํ–‰๊ณ„ํš์œผ๋กœ ํ™•์ธํ•ด์•ผ ๋น„๋กœ์†Œ ๊ฒ€์ฆ์ด ๋๋‚œ๋‹ค.

๋ฌธ์ œ๋Š” DB๋งˆ๋‹ค ์‹คํ–‰๊ณ„ํš์„ ๋ณด๋Š” ๋ฐฉ๋ฒ•์ด ์ œ๊ฐ๊ฐ์ด๋ผ๋Š” ์ ์ด๋‹ค. MySQL์˜ EXPLAIN, PostgreSQL์˜ EXPLAIN ANALYZE, Oracle์˜ DBMS_XPLAN, SQL Server์˜ ์‹คํ–‰ ๊ณ„ํš์€ ๋ช…๋ น์–ด๋„ ์ถœ๋ ฅ ํ˜•์‹๋„ ๋‹ค๋ฅด๋‹ค. ๊ทธ๋ž˜์„œ ํ•œ DB์— ์ต์ˆ™ํ•ด๋„ ๋‹ค๋ฅธ DB๋กœ ๋„˜์–ด๊ฐ€๋ฉด ๋‹ค์‹œ ๋ง‰ํžŒ๋‹ค.

์ด ๊ธ€์—์„œ๋Š” ๋„ค ๊ฐ€์ง€ ์ฃผ์š” DB(MySQL/MariaDB, PostgreSQL, Oracle, SQL Server)์—์„œ ์‹คํ–‰๊ณ„ํš์„ ์–ด๋–ป๊ฒŒ ๋ฝ‘๊ณ  ์–ด๋–ป๊ฒŒ ์ฝ๋Š”์ง€๋ฅผ ์‹ค์ œ ์ถœ๋ ฅ๊ณผ ํ•จ๊ป˜ ์ •๋ฆฌํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰์— ๋ชจ๋“  DB์— ๊ณตํ†ต์œผ๋กœ ์ ์šฉ๋˜๋Š” "์ธ๋ฑ์Šค๊ฐ€ ์•ˆ ํƒ€๋Š” ์ด์œ "๋ฅผ ์งš๋Š”๋‹ค.


1. ์‹คํ–‰๊ณ„ํš์ด๋ž€ — ์˜ตํ‹ฐ๋งˆ์ด์ €์˜ ์ž‘์—… ์ง€์‹œ์„œ

SQL์€ "๋ฌด์—‡์„ ์›ํ•˜๋Š”์ง€"๋งŒ ์ ๋Š” ์„ ์–ธํ˜• ์–ธ์–ด๋‹ค. "์–ด๋–ป๊ฒŒ ๊ฐ€์ ธ์˜ฌ์ง€"๋Š” ์˜ตํ‹ฐ๋งˆ์ด์ €(optimizer)๊ฐ€ ์ •ํ•œ๋‹ค. ๊ฐ™์€ SELECT๋ผ๋„ ํ…Œ์ด๋ธ”์„ ํ’€์Šค์บ”ํ• ์ง€, ์ธ๋ฑ์Šค๋ฅผ ํƒˆ์ง€, ์–ด๋–ค ํ…Œ์ด๋ธ”๋ถ€ํ„ฐ ์กฐ์ธํ• ์ง€ ์ˆ˜๋งŽ์€ ๊ฒฝ๋กœ๊ฐ€ ์žˆ๊ณ , ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ๊ทธ์ค‘ ๋น„์šฉ(cost)์ด ๊ฐ€์žฅ ๋‚ฎ๋‹ค๊ณ  ์ถ”์ •ํ•œ ๊ฒฝ๋กœ๋ฅผ ๊ณ ๋ฅธ๋‹ค. ์ด๋ ‡๊ฒŒ ์„ ํƒ๋œ ๊ฒฝ๋กœ๊ฐ€ ๋ฐ”๋กœ ์‹คํ–‰๊ณ„ํš์ด๋‹ค.

์—ฌ๊ธฐ์„œ ๋ฐ˜๋“œ์‹œ ๊ตฌ๋ถ„ํ•ด์•ผ ํ•  ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

  • ์˜ˆ์ƒ(estimated) ๊ณ„ํš: ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ , ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ "์ด๋ ‡๊ฒŒ ๋Œ๋ฆด ๊ฒƒ ๊ฐ™๋‹ค"๊ณ  ๋‚ด๋†“๋Š” ๊ณ„ํš. ๋น ๋ฅด๊ณ  ์•ˆ์ „ํ•˜์ง€๋งŒ ์–ด๋””๊นŒ์ง€๋‚˜ ์ถ”์ •์ด๋‹ค.
  • ์‹ค์ œ(actual) ๊ณ„ํš: ์ฟผ๋ฆฌ๋ฅผ ์‹ค์ œ๋กœ ๋Œ๋ฆฐ ๋’ค, ๊ฐ ๋‹จ๊ณ„๊ฐ€ ํ–‰์„ ๋ช‡ ๊ฐœ ์ฒ˜๋ฆฌํ–ˆ๊ณ  ์‹œ๊ฐ„์ด ์–ผ๋งˆ ๊ฑธ๋ ธ๋Š”์ง€ ์ธก์ •ํ•œ ๊ณ„ํš. ์ •ํ™•ํ•˜์ง€๋งŒ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค.

ํŠœ๋‹์˜ ํ•ต์‹ฌ์€ ์ด ๋‘˜์˜ ์ฐจ์ด๋‹ค. ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ "์ด ๋‹จ๊ณ„์—์„œ 10ํ–‰ ๋‚˜์˜ฌ ๊ฒƒ"์ด๋ผ ์˜ˆ์ƒํ–ˆ๋Š”๋ฐ ์‹ค์ œ๋กœ 100๋งŒ ํ–‰์ด ๋‚˜์™”๋‹ค๋ฉด, ํ†ต๊ณ„๊ฐ€ ํ‹€๋ ธ๊ฑฐ๋‚˜ ์„ ํƒ๋„ ํŒ๋‹จ์ด ๋น—๋‚˜๊ฐ„ ๊ฒƒ์ด๊ณ , ๊ทธ ์ง€์ ์ด ๋Œ€๊ฐœ ์„ฑ๋Šฅ ๋ฌธ์ œ์˜ ์ง„์›์ง€๋‹ค. ํฅ๋ฏธ๋กœ์šด ๊ฑด, DB๋งˆ๋‹ค ๋ถ€๋ฅด๋Š” ์ด๋ฆ„๋งŒ ๋‹ค๋ฅผ ๋ฟ ์ „๋ถ€ ์ด "์˜ˆ์ƒ vs ์‹ค์ œ"๋ฅผ ๋ณด์—ฌ์ค€๋‹ค๋Š” ์ ์ด๋‹ค.


2. ์–ด๋А DB๋“  ๋˜‘๊ฐ™์ด ๋ด์•ผ ํ•  3๊ฐ€์ง€

๋ช…๋ น์–ด๊ฐ€ ๋‹ฌ๋ผ๋„, ์‹คํ–‰๊ณ„ํš์—์„œ ์ฝ์–ด์•ผ ํ•  ํ•ต์‹ฌ์€ ์–ด๋А DB๋‚˜ ๊ฐ™๋‹ค.

  1. ์Šค์บ” ๋ฐฉ์‹ — ํ…Œ์ด๋ธ”์„ ์–ด๋–ป๊ฒŒ ์ฝ๋Š”๊ฐ€. ์ธ๋ฑ์Šค๋กœ ํ•„์š”ํ•œ ํ–‰๋งŒ ์ฐพ์•„๊ฐ€๋Š”๊ฐ€(seek / index scan), ์•„๋‹ˆ๋ฉด ์ „์ฒด๋ฅผ ํ›‘๋Š”๊ฐ€(full scan / seq scan). ํฐ ํ…Œ์ด๋ธ”์—์„œ ํ’€์Šค์บ”์ด ๋ณด์ด๋ฉด ์ผ๋‹จ ์˜์‹ฌํ•œ๋‹ค.
  2. ์กฐ์ธ ๋ฐฉ์‹ — ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์„ ์–ด๋–ป๊ฒŒ ํ•ฉ์น˜๋Š”๊ฐ€. Nested Loop(์ž‘์€ ์ง‘ํ•ฉ์— ์œ ๋ฆฌ), Hash Join(ํฐ ์ง‘ํ•ฉ·๋น„์ •๋ ฌ์— ์œ ๋ฆฌ), Merge Join(์ •๋ ฌ๋œ ์ž…๋ ฅ์— ์œ ๋ฆฌ). ๋ฐ์ดํ„ฐ ํฌ๊ธฐ์— ์•ˆ ๋งž๋Š” ์กฐ์ธ์ด ์„ ํƒ๋˜๋ฉด ๋А๋ ค์ง„๋‹ค.
  3. ์˜ˆ์ƒ vs ์‹ค์ œ ํ–‰ ์ˆ˜ — ์˜ตํ‹ฐ๋งˆ์ด์ €์˜ ์ถ”์ •์ด ํ˜„์‹ค๊ณผ ์–ผ๋งˆ๋‚˜ ๋งž๋Š”๊ฐ€. ์ฐจ์ด๊ฐ€ ํฌ๋ฉด ํ†ต๊ณ„๋ถ€ํ„ฐ ์˜์‹ฌํ•œ๋‹ค.

์‹คํ–‰๊ณ„ํš์€ ๋Œ€๋ถ€๋ถ„ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋‹ค. ๊ฐ€์žฅ ๊นŠ์ด ๋“ค์—ฌ ์“ด(๋˜๋Š” ๊ฐ€์žฅ ์•ˆ์ชฝ) ๋…ธ๋“œ๊ฐ€ ๋จผ์ € ์‹คํ–‰๋˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ ์œ„๋กœ ํ˜๋Ÿฌ ์กฐ์ธ์„ ๊ฑฐ์ณ ์ตœ์ข… ๊ฒฐ๊ณผ๊ฐ€ ๋œ๋‹ค. ์ฝ์„ ๋•Œ๋Š” ์•ˆ์ชฝ(์•„๋ž˜)๋ถ€ํ„ฐ ๋ฐ”๊นฅ(์œ„)์œผ๋กœ ๋”ฐ๋ผ๊ฐ€๋ฉด ๋œ๋‹ค.

์ด ์„ธ ๊ฐ€์ง€๋ฅผ ๊ธฐ์ค€์œผ๋กœ, ์ด์ œ DB๋ณ„๋กœ ์–ด๋–ป๊ฒŒ ๋ฝ‘๊ณ  ์ฝ๋Š”์ง€ ๋ณธ๋‹ค. ๋ชจ๋“  ์˜ˆ์ œ๋Š” orders ํ…Œ์ด๋ธ”์— customer_id ์ธ๋ฑ์Šค(idx_cust)๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค.


3. MySQL / MariaDB

๊ฐ€์žฅ ํ—ท๊ฐˆ๋ฆฌ๋Š” ๋ถ€๋ถ„๋ถ€ํ„ฐ ์งš์ž. ์˜ˆ์ƒ ๊ณ„ํš์€ ๋‘˜ ๋‹ค EXPLAIN์œผ๋กœ ๊ฐ™์ง€๋งŒ, ์‹ค์ œ ๊ณ„ํš์„ ๋ณด๋Š” ๋ช…๋ น์€ MySQL๊ณผ MariaDB๊ฐ€ ๋‹ค๋ฅด๋‹ค.

์˜ˆ์ƒ ๊ณ„ํš — EXPLAIN (๊ณตํ†ต)

EXPLAIN
SELECT * FROM orders WHERE customer_id = 12345;

์ „ํ†ต์ ์ธ ํ‘œ ํ˜•ํƒœ๋กœ ๋‚˜์˜จ๋‹ค.

+----+-------------+--------+------+---------------+----------+---------+-------+------+----------+-------+
| id | select_type | table  | type | possible_keys | key      | key_len | ref   | rows | filtered | Extra |
+----+-------------+--------+------+---------------+----------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | orders | ref  | idx_cust      | idx_cust | 4       | const |    4 |   100.00 | NULL  |
+----+-------------+--------+------+---------------+----------+---------+-------+------+----------+-------+

๋ด์•ผ ํ•  ํ•ต์‹ฌ ์ปฌ๋Ÿผ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • type — ์ ‘๊ทผ ๋ฐฉ์‹. ์ข‹์€ ์ˆœ์„œ๋กœ const > eq_ref > ref > range > index > ALL. ๋งจ ๋์˜ ALL์ด ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์œผ๋กœ, ํฐ ํ…Œ์ด๋ธ”์—์„œ ๋ณด์ด๋ฉด ์œ„ํ—˜ ์‹ ํ˜ธ๋‹ค. ์œ„ ์˜ˆ์‹œ๋Š” ref(์ธ๋ฑ์Šค๋กœ ์ฐพ์Œ)๋ผ ์–‘ํ˜ธํ•˜๋‹ค.
  • key — ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋œ ์ธ๋ฑ์Šค. NULL์ด๋ฉด ์ธ๋ฑ์Šค๋ฅผ ์ „ํ˜€ ์•ˆ ํƒ”๋‹ค๋Š” ๋œป์ด๋‹ค.
  • rows — ์ด ๋‹จ๊ณ„์—์„œ ์ฝ์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•œ ํ–‰ ์ˆ˜.
  • ExtraUsing index(์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค, ์ข‹์Œ), Using where, Using filesort·Using temporary(์ •๋ ฌ·์ž„์‹œ ํ…Œ์ด๋ธ”, ๋ฌด๊ฑฐ์›€)๋ฅผ ์ฃผ์˜ํ•ด์„œ ๋ณธ๋‹ค.

๋งŒ์•ฝ ์ธ๋ฑ์Šค๊ฐ€ ์—†์—ˆ๋‹ค๋ฉด ๊ฐ™์€ ์ฟผ๋ฆฌ๊ฐ€ ์ด๋ ‡๊ฒŒ ๋‚˜์˜จ๋‹ค. type=ALL, key=NULL, rows๊ฐ€ ํญ์ฆํ•˜๋Š” ์ „ํ˜•์ ์ธ "์ธ๋ฑ์Šค ์•ˆ ํƒ" ์‹ ํ˜ธ๋‹ค.

+----+-------------+--------+------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+--------+------+---------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | orders | ALL  | NULL          | NULL | NULL    | NULL | 1048576 |    10.00 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+---------+----------+-------------+

์‹ค์ œ ๊ณ„ํš — ์—ฌ๊ธฐ์„œ ๊ฐˆ๋ฆฐ๋‹ค

MySQL 8.0.18 ์ด์ƒ์€ EXPLAIN ANALYZE๋ฅผ ์“ด๋‹ค. ์ฟผ๋ฆฌ๋ฅผ ์‹ค์ œ๋กœ ๋Œ๋ฆฌ๊ณ , ํŠธ๋ฆฌ ํ˜•ํƒœ๋กœ ์˜ˆ์ƒ๊ณผ ์‹ค์ œ๋ฅผ ๊ฐ™์ด ๋ณด์—ฌ์ค€๋‹ค.

EXPLAIN ANALYZE
SELECT * FROM orders WHERE customer_id = 12345\G
-> Index lookup on orders using idx_cust (customer_id=12345)
   (cost=1.65 rows=4) (actual time=0.028..0.041 rows=4 loops=1)

(cost=... rows=...)๊ฐ€ ์˜ˆ์ƒ, (actual time=... rows=... loops=...)๊ฐ€ ์‹ค์ œ๋‹ค. ์—ฌ๊ธฐ์„  ์˜ˆ์ƒ 4ํ–‰ / ์‹ค์ œ 4ํ–‰์œผ๋กœ ์ž˜ ๋งž๋Š”๋‹ค.

MariaDB๋Š” EXPLAIN ANALYZE(ํŠธ๋ฆฌ)๋„ ์žˆ์ง€๋งŒ, ์ „ํ†ต์ ์œผ๋กœ๋Š” ANALYZE ๋ฌธ์„ ์“ด๋‹ค. ์ต์ˆ™ํ•œ EXPLAIN ํ‘œ์— ์‹ค์ธก ์ปฌ๋Ÿผ์ด ๋ง๋ถ™๋Š” ํ˜•ํƒœ๋ผ ๋น„๊ต๊ฐ€ ์ง๊ด€์ ์ด๋‹ค.

ANALYZE
SELECT * FROM orders WHERE customer_id = 12345;
+----+-------------+--------+------+---------------+----------+---------+-------+------+--------+----------+------------+-------+
| id | select_type | table  | type | possible_keys | key      | key_len | ref   | rows | r_rows | filtered | r_filtered | Extra |
+----+-------------+--------+------+---------------+----------+---------+-------+------+--------+----------+------------+-------+
|  1 | SIMPLE      | orders | ref  | idx_cust      | idx_cust | 4       | const |    5 |   4.00 |   100.00 |     100.00 | NULL  |
+----+-------------+--------+------+---------------+----------+---------+-------+------+--------+----------+------------+-------+

EXPLAIN์— ์—†๋˜ ๋‘ ์‹ค์ธก ์ปฌ๋Ÿผ์ด ์ถ”๊ฐ€๋œ๋‹ค.

  • r_rowsrows(์˜ˆ์ƒ)์— ๋Œ€์‘ํ•˜๋Š” ์‹ค์ œ ํ–‰ ์ˆ˜. ์œ„์—์„  ์˜ˆ์ƒ 5 / ์‹ค์ œ 4๋กœ ๊ทผ์ ‘.
  • r_filteredfiltered(์˜ˆ์ƒ ์„ ํƒ๋„)์— ๋Œ€์‘ํ•˜๋Š” ์‹ค์ œ ์„ ํƒ๋„(%).

์‹ค๋ฌด ๊ฐ๊ฐ์œผ๋กœ, ํ’€์Šค์บ”(type=ALL)์ธ๋ฐ r_filtered๊ฐ€ 15%๋ณด๋‹ค ๋‚ฎ๋‹ค๋ฉด ์ฝ์€ ํ–‰์˜ ๋Œ€๋ถ€๋ถ„์„ ๋ฒ„๋ฆฌ๊ณ  ์žˆ๋‹ค๋Š” ๋œป์ด๋ฏ€๋กœ ์ ์ ˆํ•œ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ๋‹ค. ๋” ์ž์„ธํžˆ ๋ณด๋ ค๋ฉด ANALYZE FORMAT=JSON์„ ์“ด๋‹ค.


4. PostgreSQL

PostgreSQL์€ ๋ช…๋ น ์ฒด๊ณ„๊ฐ€ ๊ฐ€์žฅ ๊น”๋”ํ•˜๋‹ค.

์˜ˆ์ƒ ๊ณ„ํš — EXPLAIN

EXPLAIN
SELECT * FROM orders WHERE customer_id = 12345;
                              QUERY PLAN
-----------------------------------------------------------------------
 Index Scan using idx_cust on orders  (cost=0.29..8.31 rows=5 width=64)
   Index Cond: (customer_id = 12345)
  • cost=0.29..8.31์‹œ์ž‘ ๋น„์šฉ..์ด ๋น„์šฉ(๋””์Šคํฌ ํŽ˜์ด์ง€ ํŽ˜์น˜ ๋‹จ์œ„์˜ ์ถ”์ •๊ฐ’).
  • rows=5 — ์˜ˆ์ƒ ํ–‰ ์ˆ˜, width=64 — ํ–‰ ํ‰๊ท  ๋ฐ”์ดํŠธ.
  • Index Scan — ์ธ๋ฑ์Šค๋ฅผ ํƒ”๋‹ค๋Š” ๋œป. ์ด ์ž๋ฆฌ์— Seq Scan์ด ๋ณด์ด๋ฉด ์ธ๋ฑ์Šค๋ฅผ ๋ชป/์•ˆ ํƒ„ ๊ฒƒ์ด๋‹ค.

์‹ค์ œ ๊ณ„ํš — EXPLAIN ANALYZE

EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders WHERE customer_id = 12345;
                              QUERY PLAN
-----------------------------------------------------------------------
 Index Scan using idx_cust on orders  (cost=0.29..8.31 rows=5 width=64)
                                       (actual time=0.018..0.024 rows=4 loops=1)
   Index Cond: (customer_id = 12345)
   Buffers: shared hit=3
 Planning Time: 0.072 ms
 Execution Time: 0.041 ms
  • actual time=0.018..0.024 — ์‹ค์ œ ์‹œ์ž‘..์ข…๋ฃŒ ์‹œ๊ฐ„(ms), rows=4 — ์‹ค์ œ ํ–‰ ์ˆ˜, loops=1 — ์ด ๋…ธ๋“œ๊ฐ€ ๋ฐ˜๋ณต๋œ ํšŸ์ˆ˜.
  • Buffers: shared hit=3 — ์บ์‹œ์—์„œ ์ฝ์€ ๋ธ”๋ก ์ˆ˜(hit์€ ์บ์‹œ ์ ์ค‘, read๋Š” ๋””์Šคํฌ).

์ฃผ์˜ํ•  ํ•จ์ •์ด loops๋‹ค. Nested Loop ์•ˆ์ชฝ ๋…ธ๋“œ๋Š” ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐ˜๋ณต๋˜๋Š”๋ฐ, ํ‘œ์‹œ๋˜๋Š” rows๋Š” ๋ฐ˜๋ณต๋‹น ํ‰๊ท ์ด๋‹ค. ์‹ค์ œ ์ด ์ฒ˜๋ฆฌ ํ–‰์ˆ˜๋Š” rows × loops๋กœ ๊ณ„์‚ฐํ•ด์•ผ ํ•œ๋‹ค.

์ฐธ๊ณ ๋กœ PostgreSQL 18๋ถ€ํ„ฐ๋Š” EXPLAIN ANALYZE์— BUFFERS๊ฐ€ ๊ธฐ๋ณธ ํฌํ•จ๋œ๋‹ค. 17 ์ดํ•˜์—์„œ๋Š” ์œ„์ฒ˜๋Ÿผ BUFFERS๋ฅผ ์ง์ ‘ ๋ถ™์—ฌ์•ผ I/O ์ •๋ณด๊ฐ€ ๋‚˜์˜จ๋‹ค. ์ถœ๋ ฅ์€ FORMAT JSON/XML/YAML๋กœ๋„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.


5. Oracle

Oracle์€ ๊ณ„ํš์„ ๋งŒ๋“œ๋Š” ๋ช…๋ น๊ณผ ๊ทธ๊ฑธ ๋ณด๊ธฐ ์ข‹๊ฒŒ ์ถœ๋ ฅํ•˜๋Š” ๋ช…๋ น(DBMS_XPLAN)์ด ๋”ฐ๋กœ๋‹ค.

์˜ˆ์ƒ ๊ณ„ํš — EXPLAIN PLAN

EXPLAIN PLAN FOR
SELECT * FROM orders WHERE customer_id = 12345;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY());
---------------------------------------------------------------------------------
| Id | Operation                    | Name     | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
|  0 | SELECT STATEMENT             |          |    4 |   240 |     3   (0)|      |
|  1 |  TABLE ACCESS BY INDEX ROWID | ORDERS   |    4 |   240 |     3   (0)|      |
|* 2 |   INDEX RANGE SCAN           | IDX_CUST |    4 |       |     1   (0)|      |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("CUSTOMER_ID"=12345)

Operation(TABLE ACCESS FULL=ํ’€์Šค์บ”, INDEX RANGE SCAN, TABLE ACCESS BY INDEX ROWID ๋“ฑ), Rows(์˜ˆ์ƒ ํ–‰ ์ˆ˜, E-Rows), Cost ์ปฌ๋Ÿผ์ด ๋‚˜์˜จ๋‹ค. ๋‹จ, ์ด๊ฑด ๋ฐ”์ธ๋“œ ๋ณ€์ˆ˜ ๊ฐ’์„ ๋ฌด์‹œํ•œ ์ถ”์ •์ด๋‹ค.

์‹ค์ œ ๊ณ„ํš — GATHER_PLAN_STATISTICS

์‹ค์ธก์„ ๋ณด๋ ค๋ฉด ์ฟผ๋ฆฌ์— GATHER_PLAN_STATISTICS ํžŒํŠธ๋ฅผ ๋„ฃ์–ด ์‹คํ–‰ํ•˜๊ณ , DISPLAY_CURSOR๋ฅผ ALLSTATS LAST ํฌ๋งท์œผ๋กœ ์ถœ๋ ฅํ•œ๋‹ค.

SELECT /*+ GATHER_PLAN_STATISTICS */ *
FROM orders WHERE customer_id = 12345;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(FORMAT => 'ALLSTATS LAST'));
-------------------------------------------------------------------------------------------------
| Id | Operation                    | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------
|  0 | SELECT STATEMENT             |          |      1 |        |      4  |00:00:00.01 |       5 |
|  1 |  TABLE ACCESS BY INDEX ROWID | ORDERS   |      1 |      4 |      4  |00:00:00.01 |       5 |
|* 2 |   INDEX RANGE SCAN           | IDX_CUST |      1 |      4 |      4  |00:00:00.01 |       2 |
-------------------------------------------------------------------------------------------------
  • E-Rows — ์˜ตํ‹ฐ๋งˆ์ด์ € ์˜ˆ์ƒ ํ–‰ ์ˆ˜, A-Rows — ์‹ค์ œ ํ–‰ ์ˆ˜.
  • Starts — ํ•ด๋‹น ๋‹จ๊ณ„๊ฐ€ ์‹คํ–‰๋œ ํšŸ์ˆ˜(PostgreSQL์˜ loops์— ํ•ด๋‹น).
  • Buffers — ์ฝ์€ ๋ธ”๋ก ์ˆ˜.

E-Rows์™€ A-Rows์˜ ์ฐจ์ด๊ฐ€ ํฌ๊ฒŒ ๋ฒŒ์–ด์ง€๋Š” ์ฒซ ๋‹จ๊ณ„๊ฐ€ ๋Œ€๊ฐœ ๋ฌธ์ œ์˜ ์ถœ๋ฐœ์ ์ด๋‹ค. SQL*Plus๋‚˜ SQLcl์—์„œ๋Š” SET AUTOTRACE ON์œผ๋กœ ๊ฐ„๋‹จํžˆ ๊ณ„ํš๊ณผ ํ†ต๊ณ„๋ฅผ ๊ฐ™์ด ๋ณผ ์ˆ˜๋„ ์žˆ๋‹ค.

๋˜ ํ•˜๋‚˜, ์ถœ๋ ฅ ํ•˜๋‹จ Predicate Information์ด ์ธ๋ฑ์Šค ํ™œ์šฉ ํŒ๋‹จ์˜ ๊ฒฐ์ •์  ๋‹จ์„œ๋‹ค. ์กฐ๊ฑด์ด access๋กœ ์žกํžˆ๋ฉด ์ธ๋ฑ์Šค ํƒ์ƒ‰์„ ์ง์ ‘ ๊ตฌ๋™ํ•œ๋‹ค๋Š” ๋œป(์ข‹์Œ)์ด๊ณ , filter๋กœ ์žกํžˆ๋ฉด ํ–‰์„ ๋‹ค ๊ฐ€์ ธ์˜จ ๋’ค ๊ฑธ๋Ÿฌ๋‚ธ๋‹ค๋Š” ๋œป(์ธ๋ฑ์Šค๋ฅผ ๊ธฐ๋Œ€ํ–ˆ๋‹ค๋ฉด ๋‚˜์จ)์ด๋‹ค.


6. SQL Server

SQL Server๋Š” SSMS(Management Studio)์˜ ๊ทธ๋ž˜ํ”ฝ ์‹คํ–‰ ๊ณ„ํš์ด ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ์Šคํฌ๋ฆฝํŠธ๋กœ๋„ ๋ชจ๋‘ ๋ฝ‘์„ ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ์ƒ ๊ณ„ํš — SHOWPLAN

SET SHOWPLAN_TEXT ON;
GO
SELECT * FROM Orders WHERE CustomerID = 12345;
GO
SET SHOWPLAN_TEXT OFF;
GO
StmtText
------------------------------------------------------------------------------
  |--Index Seek(OBJECT:([Sales].[Orders].[idx_cust]),
                SEEK:([Orders].[CustomerID]=(12345)) ORDERED FORWARD)

Index Seek์ด ๋ณด์ด๋ฉด ์ธ๋ฑ์Šค๋ฅผ ์ •ํ™•ํžˆ ์ฐพ์•„๊ฐ„ ๊ฒƒ์ด๋‹ค. ์ด ์ž๋ฆฌ์— Index Scan์ด๋‚˜ Clustered Index Scan/Table Scan์ด ํฐ ํ…Œ์ด๋ธ”์—์„œ ๋ณด์ด๋ฉด ์ธ๋ฑ์Šค๋ฅผ ๋ชป ํƒ€๋Š” ํ˜•ํƒœ๋‹ค. SSMS์—์„œ๋Š” Ctrl+L๋กœ ๊ทธ๋ž˜ํ”ฝ ์˜ˆ์ƒ ๊ณ„ํš์„ ๋ฐ”๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์‹ค์ œ ๋ฆฌ์†Œ์Šค — STATISTICS IO / TIME

์‹ค์ธก์—์„œ ๊ฐ€์žฅ ์ž์ฃผ ๋ณด๋Š” ๊ฑด ๋…ผ๋ฆฌ์  ์ฝ๊ธฐ(logical reads)๋‹ค. ๊ฐ™์€ ์ฟผ๋ฆฌ๋ฅผ ํŠœ๋‹ํ•˜๋ฉฐ ์ด ์ˆซ์ž๊ฐ€ ์ค„๋ฉด ๋” ์ ์€ ํŽ˜์ด์ง€๋ฅผ ์ฝ๋Š”๋‹ค๋Š” ๋œป์ด๋ผ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์ง€ํ‘œ๋‹ค.

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
SELECT * FROM Orders WHERE CustomerID = 12345;
Table 'Orders'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 1 ms.

์ธ๋ฑ์Šค๊ฐ€ ์—†์œผ๋ฉด ๊ฐ™์€ ์ฟผ๋ฆฌ๊ฐ€ Clustered Index Scan์œผ๋กœ ๋–จ์–ด์ง€๋ฉด์„œ logical reads๊ฐ€ ์ˆ˜์ฒœ์œผ๋กœ ๋›ด๋‹ค. ๊ทธ ์ˆซ์ž ์ž์ฒด๊ฐ€ "์ด ์ธ๋ฑ์Šค๊ฐ€ ํšจ๊ณผ ์žˆ๋‹ค"์˜ ์ฆ๊ฑฐ๊ฐ€ ๋œ๋‹ค. ์‹ค์ œ ๊ทธ๋ž˜ํ”ฝ ๊ณ„ํš์€ Ctrl+M ํ›„ ์‹คํ–‰(๋˜๋Š” SET STATISTICS XML ON)์œผ๋กœ ๋ณธ๋‹ค.

๊ทธ๋ž˜ํ”ฝ ๊ณ„ํš์„ ๋น ๋ฅด๊ฒŒ ํ›‘์„ ๋•Œ์˜ ์š”๋ น ๋ช‡ ๊ฐ€์ง€.

  • ํ™”์‚ดํ‘œ ๋‘๊ป˜ = ํ๋ฅด๋Š” ํ–‰ ์ˆ˜. ๊ฐ‘์ž๊ธฐ ๊ตต์–ด์ง€๋Š” ์ง€์ ์ด ๋ณดํ†ต ๋ฒ”์ธ์ด๋‹ค.
  • Key Lookup์ด ๋Œ€๋Ÿ‰ ๋ฐ˜๋ณต๋˜๋ฉด ๋น„์‹ธ๋‹ค → ํ•„์š”ํ•œ ์ปฌ๋Ÿผ์„ INCLUDEํ•œ ์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค๋กœ ํ•ด๊ฒฐํ•œ๋‹ค.
  • ์—ฐ์‚ฐ์ž ๋น„์šฉ %๋Š” ์ถ”์ •์ด๋ผ ๊ทธ๋Œ€๋กœ ๋ฏฟ์ง€ ๋ง๊ณ , ์‹ค์ œ ํ–‰ ์ˆ˜·๋…ผ๋ฆฌ์  ์ฝ๊ธฐ๋ฅผ ํ•จ๊ป˜ ๋ณธ๋‹ค.
  • ๊ทธ๋ž˜ํ”ฝ ๊ณ„ํš์˜ ๋…ธ๋ž€ ๊ฒฝ๊ณ  ์•„์ด์ฝ˜๊ณผ ๋…น์ƒ‰ ๋ˆ„๋ฝ ์ธ๋ฑ์Šค(missing index) ํžŒํŠธ๋„ ์ข‹์€ ์ถœ๋ฐœ์ ์ด๋‹ค.

7. ์ธ๋ฑ์Šค๊ฐ€ ์•ˆ ํƒ€๋Š” ์ด์œ  ์ฐพ๊ธฐ

์—ฌ๊ธฐ๊นŒ์ง€๊ฐ€ ๋„๊ตฌ๋ผ๋ฉด, ์ด์ œ ๋ณธ๋ก ์ด๋‹ค. ์‹คํ–‰๊ณ„ํš์—์„œ ํ’€์Šค์บ”(๋˜๋Š” filter, Index Scan)์ด ๋ณด์ผ ๋•Œ, ์ธ๋ฑ์Šค๊ฐ€ ์žˆ๋Š”๋ฐ๋„ ์•ˆ ํƒ€๋Š” ์ด์œ ๋Š” DB๊ฐ€ ๋‹ฌ๋ผ๋„ ๋Œ€๊ฐœ ๊ฐ™์€ ํŒจํ„ด์ด๋‹ค.

  1. WHERE ์ปฌ๋Ÿผ์— ํ•จ์ˆ˜๋‚˜ ์—ฐ์‚ฐ์„ ์”Œ์›€. WHERE YEAR(created_at) = 2024๋‚˜ WHERE price + 1000 > 5000์ฒ˜๋Ÿผ ์ปฌ๋Ÿผ์„ ๊ฐ€๊ณตํ•˜๋ฉด ์ธ๋ฑ์Šค๋ฅผ ๋ชป ์“ด๋‹ค(SARGableํ•˜์ง€ ์•Š์Œ). ์ปฌ๋Ÿผ์€ ๊ทธ๋Œ€๋กœ ๋‘๊ณ  ์ƒ์ˆ˜ ์ชฝ์„ ๊ฐ€๊ณตํ•ด์•ผ ํ•œ๋‹ค → WHERE created_at >= '2024-01-01'.
  2. ํƒ€์ž… ๋ถˆ์ผ์น˜๋กœ ์ธํ•œ ์•”๋ฌต์  ํ˜•๋ณ€ํ™˜. ๋ฌธ์ž์—ด ์ปฌ๋Ÿผ์— ์ˆซ์ž๋ฅผ ๋น„๊ตํ•˜๊ฑฐ๋‚˜ ๊ทธ ๋ฐ˜๋Œ€๋ฉด, DB๊ฐ€ ํ•œ์ชฝ์„ ๋ณ€ํ™˜ํ•˜๋ฉด์„œ ์ธ๋ฑ์Šค๊ฐ€ ๋ฌด๋ ฅํ™”๋œ๋‹ค. Oracle์˜ Predicate๊ฐ€ filter๋กœ ๋ฐ”๋€Œ๋Š” ์ „ํ˜•์  ์›์ธ์ด๋‹ค.
  3. ์„ ํƒ๋„๊ฐ€ ๋‚ฎ์Œ. ์กฐ๊ฑด์— ๋งž๋Š” ํ–‰์ด ํ…Œ์ด๋ธ”์˜ ์ƒ๋‹น ๋น„์œจ์ด๋ฉด, ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ์ธ๋ฑ์Šค ํƒ์ƒ‰๋ณด๋‹ค ํ’€์Šค์บ”์ด ๋” ์‹ธ๋‹ค๊ณ  ํŒ๋‹จํ•œ๋‹ค. ์ด๊ฑด ์˜คํŒ์ด ์•„๋‹ˆ๋ผ ์ •์ƒ์ ์ธ ์„ ํƒ์ผ ๋•Œ๊ฐ€ ๋งŽ๋‹ค.
  4. ํ†ต๊ณ„๊ฐ€ ์˜ค๋ž˜๋๊ฑฐ๋‚˜ ๋ถ€์ •ํ™•ํ•จ. ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ํ†ต๊ณ„๋กœ ํ–‰ ์ˆ˜๋ฅผ ์ถ”์ •ํ•œ๋‹ค. ํ†ต๊ณ„๊ฐ€ ์–ด๊ธ‹๋‚˜๋ฉด ์˜ˆ์ƒ๊ณผ ์‹ค์ œ(rows vs r_rows, E-Rows vs A-Rows)๊ฐ€ ํฌ๊ฒŒ ๋ฒŒ์–ด์ง€๊ณ  ์ž˜๋ชป๋œ ๊ณ„ํš์„ ๊ณ ๋ฅธ๋‹ค → ํ†ต๊ณ„๋ฅผ ๊ฐฑ์‹ ํ•œ๋‹ค(ANALYZE TABLE, DBMS_STATS, UPDATE STATISTICS).
  5. ์„ ํ–‰ ์™€์ผ๋“œ์นด๋“œ LIKE. LIKE '%๊ฒ€์ƒ‰์–ด'๋Š” ์ธ๋ฑ์Šค๋ฅผ ๋ชป ํƒ„๋‹ค. ๋’ค์ชฝ ์™€์ผ๋“œ์นด๋“œ('๊ฒ€์ƒ‰์–ด%')๋Š” ํƒˆ ์ˆ˜ ์žˆ๋‹ค.
  6. ๋ณตํ•ฉ ์ธ๋ฑ์Šค์˜ ์„ ๋‘ ์ปฌ๋Ÿผ ๋ˆ„๋ฝ. (a, b, c) ์ธ๋ฑ์Šค๋Š” a๋ถ€ํ„ฐ ์กฐ๊ฑด์ด ์žˆ์–ด์•ผ ํšจ์œจ์ ์œผ๋กœ ํƒ„๋‹ค. b๋งŒ์œผ๋กœ ๊ฒ€์ƒ‰ํ•˜๋ฉด ์ธ๋ฑ์Šค๋ฅผ ์ œ๋Œ€๋กœ ๋ชป ์“ด๋‹ค.

๊ฐ DB์—์„œ "์ธ๋ฑ์Šค ์•ˆ ํƒ"์ด ์–ด๋–ป๊ฒŒ ๋ณด์ด๋Š”์ง€ ์‹ ํ˜ธ๋ฅผ ์š”์•ฝํ•˜๋ฉด ์ด๋ ‡๋‹ค.

  • MySQL / MariaDB: key๊ฐ€ NULL, type์ด ALL.
  • PostgreSQL: Index Scan์ด์–ด์•ผ ํ•  ์ž๋ฆฌ์— Seq Scan.
  • Oracle: Predicate๊ฐ€ access๊ฐ€ ์•„๋‹ˆ๋ผ filter, ๊ทธ๋ฆฌ๊ณ  TABLE ACCESS FULL.
  • SQL Server: Index Scan·Table Scan, ๋…ธ๋ž€ ๊ฒฝ๊ณ ๋‚˜ ๋ˆ„๋ฝ ์ธ๋ฑ์Šค ํžŒํŠธ.

8. ๋„ค DB ๋น„๊ต

DB ์˜ˆ์ƒ ๊ณ„ํš (์‹คํ–‰ ์•ˆ ํ•จ) ์‹ค์ œ ๊ณ„ํš (์‹คํ–‰ํ•จ) ์‹ค์ œ ํ–‰ ์ˆ˜ ์ปฌ๋Ÿผ ์ธ๋ฑ์Šค ๋ฏธ์‚ฌ์šฉ ์‹ ํ˜ธ
MySQL EXPLAIN EXPLAIN ANALYZE (ํŠธ๋ฆฌ) actual rows key=NULL, type=ALL
MariaDB EXPLAIN ANALYZE ๋ฌธ r_rows key=NULL, type=ALL
PostgreSQL EXPLAIN EXPLAIN ANALYZE actual rows Seq Scan
Oracle EXPLAIN PLAN + DISPLAY ํžŒํŠธ + DISPLAY_CURSOR A-Rows Predicate๊ฐ€ filter
SQL Server SHOWPLAN_XML / Ctrl+L STATISTICS XML / Ctrl+M Actual Number of Rows Index/Table Scan, ๋…ธ๋ž€ ๊ฒฝ๊ณ 

๋งˆ์น˜๋ฉฐ

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์ „์— ๋ณด๋Š” ๊ฒƒ๋“ค์—์„œ "๋А๋ฆฌ๋‹ค๊ณ  ๋ฌด์ž‘์ • ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ๋ง๋ผ"๊ณ  ํ–ˆ๋‹ค. ์ด ๊ธ€์€ ๊ทธ ์ง์ด ๋˜๋Š” ๊ธ€์ด๋‹ค. ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค๋ฉด, ์‹คํ–‰๊ณ„ํš์œผ๋กœ ๊ทธ๊ฒŒ ์‹ค์ œ๋กœ ์“ฐ์ด๋Š”์ง€ ๋ฐ˜๋“œ์‹œ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. ๋งŒ๋“ค์—ˆ๋‹ค๊ณ  ๋์ด ์•„๋‹ˆ๋ผ, ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ๊ทธ ์ธ๋ฑ์Šค๋ฅผ ๊ณจ๋ž๋Š”์ง€๊นŒ์ง€ ๋ด์•ผ ๊ฒ€์ฆ์ด ๋๋‚œ๋‹ค.

DB๋งˆ๋‹ค ๋ช…๋ น์–ด๋Š” EXPLAIN, ANALYZE, DBMS_XPLAN, SET STATISTICS๋กœ ์ œ๊ฐ๊ฐ์ด๊ณ  ์ถœ๋ ฅ ํ˜•ํƒœ๋„ ํ‘œ์™€ ํŠธ๋ฆฌ๋กœ ๊ฐˆ๋ฆฐ๋‹ค. ํ•˜์ง€๋งŒ ์ฝ๋Š” ๋ˆˆ์€ ํ•˜๋‚˜๋‹ค. ์Šค์บ” ๋ฐฉ์‹, ์กฐ์ธ ๋ฐฉ์‹, ๊ทธ๋ฆฌ๊ณ  ์˜ˆ์ƒ๊ณผ ์‹ค์ œ ํ–‰ ์ˆ˜์˜ ์ฐจ์ด. ํŠนํžˆ ์˜ˆ์ƒ๊ณผ ์‹ค์ œ๊ฐ€ ํฌ๊ฒŒ ๋ฒŒ์–ด์ง€๋Š” ์ฒซ ์ง€์ ์„ ์ฐพ๋Š” ์Šต๊ด€๋งŒ ๋“ค์ด๋ฉด, ์–ด๋А DB๋กœ ์˜ฎ๊ฒจ๊ฐ€๋„ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋ฌธ์ œ์˜ ์ง„์›์ง€๋ฅผ ์งš์„ ์ˆ˜ ์žˆ๋‹ค.


์ฐธ๊ณ  ์ถœ์ฒ˜