infra & network

[Lecture] ์Šคํ”„๋ง๋ถ€ํŠธ๋กœ ์ง์ ‘ ๋งŒ๋“ค๋ฉด์„œ ๋ฐฐ์šฐ๋Š” ๋Œ€๊ทœ๋ชจ ์‹œ์Šคํ…œ ์„ค๊ณ„ - (2)

devJK93 2025. 4. 20. 18:25

๐Ÿ“‘ ํŽ˜์ด์ง•์ฒ˜๋ฆฌ์™€ ๋ฌดํ•œ์Šคํฌ๋กค

๐Ÿ“Œ ๋Œ€๊ทœ๋ชจ ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก ์กฐํšŒ๋Š” ์™œ ๋ณต์žกํ• ๊นŒ?

  • ๋ชจ๋“  ๊ฒŒ์‹œ๊ธ€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ์— ์กฐํšŒํ•ด์„œ ๋ณด์—ฌ์ค„ ์ˆ˜๋Š” ์—†๋‹ค.
    • ๋ฉ”๋ชจ๋ฆฌ, ๋„คํŠธ์›Œํฌ, ์‹œ์Šคํ…œ ์„ฑ๋Šฅ ๋“ฑ์˜ ์ œ์•ฝ ๋•Œ๋ฌธ์ด๋‹ค.
  • ๋”ฐ๋ผ์„œ ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

โœ… ํŽ˜์ด์ง•์„ ์™œ ๊ผญ ํ•ด์•ผ ํ•˜๋‚˜?

  • ์„œ๋ฒ„์—์„œ ๋ชจ๋“  ๊ฒŒ์‹œ๊ธ€ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ๊บผ๋ฒˆ์— ๋ถˆ๋Ÿฌ์™€ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ฆฌ๋Š” ๊ฒƒ์€ ๋น„ํšจ์œจ์ ์ด๋‹ค.
    • ๋””์Šคํฌ์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ๋กœ ์ „๋ถ€ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฑด ๋А๋ฆฌ๊ณ , ๋””์Šคํฌ I/O ๋น„์šฉ๋„ ํฌ๋‹ค.
    • ๋ฉ”๋ชจ๋ฆฌ ํ•œ๊ณ„๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด OutOfMemoryError(OOM)๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋”ฐ๋ผ์„œ DB์—์„œ ํŠน์ • ํŽ˜์ด์ง€๋งŒ ์ถ”์ถœํ•˜๋Š” ๋ฐฉ์‹์ด ํ•„์š”ํ•˜๋‹ค.
    • ์ด๋ฅผ ์œ„ํ•ด ํŽ˜์ด์ง• ์ฟผ๋ฆฌ๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค. (LIMIT, OFFSET, WHERE id < ? ๋“ฑ)

๐Ÿ”„ ํŽ˜์ด์ง• ๋ฐฉ์‹์˜ ์ข…๋ฅ˜

ํŽ˜์ด์ง• ๋ฐฉ์‹์€ ํด๋ผ์ด์–ธํŠธ๋‚˜ ์„œ๋น„์Šค ํŠน์„ฑ์— ๋”ฐ๋ผ ํฌ๊ฒŒ 2๊ฐ€์ง€๋กœ ๋‚˜๋‰œ๋‹ค:

1. ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐฉ์‹

  • ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋™ํ•  ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์„ ํƒํ•จ
  • ์˜ˆ: 1ํŽ˜์ด์ง€, 2ํŽ˜์ด์ง€, 3ํŽ˜์ด์ง€ ...
  • ์žฅ์ :
    • ์›ํ•˜๋Š” ํŽ˜์ด์ง€๋กœ ๋ฐ”๋กœ ์ด๋™ ๊ฐ€๋Šฅ
    • ์ „์ฒด ํŽ˜์ด์ง€ ์ˆ˜๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ์ข‹์Œ
  • ์˜ˆ์‹œ:
    • Google ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํ•˜๋‹จ ํŽ˜์ด์ง€๋„ค์ด์…˜ UI

2. ๋ฌดํ•œ ์Šคํฌ๋กค ๋ฐฉ์‹

  • ์‚ฌ์šฉ์ž๊ฐ€ ์Šคํฌ๋กค์„ ๋‚ด๋ฆฌ๋ฉด ์ž๋™์œผ๋กœ ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐฉ์‹
  • ์žฅ์ :
    • UX๊ฐ€ ์ž์—ฐ์Šค๋Ÿฌ์›Œ์„œ ๋ชจ๋ฐ”์ผ ํ™˜๊ฒฝ์— ์ ํ•ฉ
    • "๋”๋ณด๊ธฐ" ๋ฒ„ํŠผ์œผ๋กœ ๊ตฌํ˜„๋˜๊ธฐ๋„ ํ•จ
  • ์ฃผ๋กœ SNS, ํ”ผ๋“œ ๊ธฐ๋ฐ˜ UI์— ๋งŽ์ด ์‚ฌ์šฉ๋จ

โœ… ๋งˆ๋ฌด๋ฆฌ

ํŽ˜์ด์ง•์€ ๋‹จ์ˆœํžˆ ๋ณด๊ธฐ ํŽธํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ๊ธฐ๋Šฅ์ด ์•„๋‹ˆ๋ผ,
์„ฑ๋Šฅ๊ณผ ์•ˆ์ •์„ฑ์„ ์œ„ํ•ด ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ ์„ค๊ณ„ ์š”์†Œ๋‹ค.
ํŠนํžˆ ๋Œ€๊ทœ๋ชจ ๊ฒŒ์‹œ๊ธ€ ์‹œ์Šคํ…œ์—์„œ๋Š” DB, ๋ฉ”๋ชจ๋ฆฌ, ์‚ฌ์šฉ์ž ๊ฒฝํ—˜๊นŒ์ง€ ๊ณ ๋ คํ•œ ์ •๊ตํ•œ ํŽ˜์ด์ง• ์„ค๊ณ„๊ฐ€ ์ค‘์š”ํ•˜๋‹ค.


๐Ÿ“‘ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐฉ์‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ

select * from article where board_id = 1 order by created_at desc limit 30 offset 90;
30 rows in set (3.81 sec) -- ๊ณ ์ž‘ 1,200๋งŒ ๊ฑด์˜ ๋ฐ์ดํ„ฐ์—์„œ 30๊ฑด์„ ์กฐํšŒํ•˜๋Š”๋ฐ ๋ฌด๋ ค 4์ดˆ!

 

์ข‹์•„! ์ด๋ฒˆ ์Šฌ๋ผ์ด๋“œ๋“ค์—์„œ๋Š” ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐฉ์‹ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ๊ฐœ๋…๊ณผ SQL ์ž‘์„ฑ ๋ฐฉ๋ฒ•๊นŒ์ง€ ์„ค๋ช…ํ•˜๊ณ  ์žˆ์–ด. ๋ธ”๋กœ๊ทธ์— ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์š”์•ฝํ•ด์ค„๊ฒŒ๐Ÿ‘‡

 

๐Ÿ“„ ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก ์กฐํšŒ – ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐฉ์‹

โœ… ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐฉ์‹์ด๋ž€?

  • ํŽ˜์ด์ง€๋ฅผ ๋ฒˆํ˜ธ๋กœ ๊ตฌ๋ถ„ํ•ด์„œ ์กฐํšŒํ•˜๋Š” ๋ฐฉ์‹
  • ์‚ฌ์šฉ์ž๊ฐ€ N๋ฒˆ ํŽ˜์ด์ง€๋ฅผ ์š”์ฒญํ•˜๋ฉด → ๊ทธ์— ํ•ด๋‹นํ•˜๋Š” ๊ฒŒ์‹œ๊ธ€ M๊ฐœ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ตฌ์กฐ

โœ… ํ•„์š”ํ•œ ์ •๋ณด

  1. N๋ฒˆ ํŽ˜์ด์ง€์—์„œ M๊ฐœ์˜ ๊ฒŒ์‹œ๊ธ€์„ ๋ณด์—ฌ์ค€๋‹ค๋Š” ๊ธฐ์ค€
  2. ์ „์ฒด ๊ฒŒ์‹œ๊ธ€ ์ˆ˜๋ฅผ ์•Œ์•„์•ผ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์Œ
    • ์˜ˆ: ํŽ˜์ด์ง€๋‹น 30๊ฐœ, ์ด 94๊ฐœ์˜ ๊ฒŒ์‹œ๊ธ€์ด๋ฉด → 4ํŽ˜์ด์ง€๊นŒ์ง€ ์žˆ์Œ
    • ์ด๊ฑธ ๋ฐ”ํƒ•์œผ๋กœ ํด๋ผ์ด์–ธํŠธ UI์—์„œ ํŽ˜์ด์ง€ ๋ฒ„ํŠผ์„ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Œ

โœ… ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐฉ์‹์˜ SQL ์ž‘์„ฑ๋ฒ•

  • SQL์˜ LIMIT, OFFSET ๋ฌธ๋ฒ•์„ ํ™œ์šฉ
  • LIMIT: ํ•œ ํŽ˜์ด์ง€์— ๋ณด์—ฌ์ค„ ๊ฐœ์ˆ˜ (M)
  • OFFSET: ๋ช‡ ๊ฐœ ๊ฑด๋„ˆ๋›ธ์ง€ → (N - 1) * M
-- ์ตœ์‹ ์ˆœ์œผ๋กœ ํŠน์ • ํŽ˜์ด์ง€์˜ ๊ฒŒ์‹œ๊ธ€ ์กฐํšŒ
select * 
from article
where board_id = {board_id}              -- ๊ฒŒ์‹œํŒ ID
order by created_at desc                 -- ์ตœ์‹ ์ˆœ ์ •๋ ฌ
limit {limit} offset {(N - 1) * limit};  -- N๋ฒˆ ํŽ˜์ด์ง€์—์„œ M๊ฐœ ์กฐํšŒ

โœ… ์ฐธ๊ณ : ์„ฑ๋Šฅ๊ณผ ์ƒค๋”ฉ ๊ณ ๋ ค

  • board_id๋ฅผ shard key๋กœ ์‚ฌ์šฉํ•˜๋ฉด,
    • ๊ฐ ๊ฒŒ์‹œํŒ์— ๋Œ€ํ•œ ์ฟผ๋ฆฌ๋Š” ๋‹จ์ผ ์ƒค๋“œ์—์„œ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
    • ํ™•์žฅ์„ฑ, ์„ฑ๋Šฅ์— ์œ ๋ฆฌํ•จ

๐Ÿ’ฌ ๋งˆ๋ฌด๋ฆฌ ์š”์•ฝ

ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐฉ์‹์€ ์ง๊ด€์ ์ด๊ณ  UI ๊ตฌ์„ฑ์— ์ข‹์ง€๋งŒ,
OFFSET์ด ํด์ˆ˜๋ก ์„ฑ๋Šฅ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ,
๊ทœ๋ชจ๊ฐ€ ํฌ๋ฉด Cursor ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง• ๋ฐฉ์‹๋„ ํ•จ๊ป˜ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค.

์›ํ•˜๋ฉด ์ด์–ด์„œ "Cursor ๊ธฐ๋ฐ˜ ๋ฌดํ•œ ์Šคํฌ๋กค ํŽ˜์ด์ง•" ๋ฐฉ์‹๋„ ์š”์•ฝํ•ด์ค„๊ฒŒ!
๋˜๋Š” ์ด ๋‚ด์šฉ์„ Markdown/HTML๋กœ ๋ฐ”๊ฟ”์ค„ ์ˆ˜๋„ ์žˆ์–ด.


๐Ÿ“‘ EXPLAIN์„ ํ™œ์šฉํ•ด์„œ Query Plan ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

explain select * from article where board_id = 1 order by created_at desc limit 30 offset 90;
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-----------------------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows     | filtered | Extra                       |
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-----------------------------+
|  1 | SIMPLE      | article | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 12548751 |    10.00 | Using where; Using filesort |
+----+-------------+---------+------------+------+---------------+------+---------+------+----------+----------+-----------------------------+

 

์ข‹์•„! ์ด EXPLAIN ๊ฒฐ๊ณผ๋Š” SQL ์„ฑ๋Šฅ ๋ถ„์„์„ ์œ„ํ•œ ํ•ต์‹ฌ ๋„๊ตฌ์•ผ.
์ง€๊ธˆ ๋„ˆ๊ฐ€ ์กฐํšŒํ•œ ์ฟผ๋ฆฌ:

SELECT * FROM article
WHERE board_id = 1
ORDER BY created_at DESC
LIMIT 30 OFFSET 90;

 

์ด ์ฟผ๋ฆฌ๋ฅผ EXPLAIN์œผ๋กœ ๋ถ„์„ํ•œ ๊ฒฐ๊ณผ๋ฅผ ์š”์•ฝํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์•„๐Ÿ‘‡

 

๐Ÿ“Œ EXPLAIN ๋ถ„์„ ์š”์•ฝ

ํ•ญ๋ชฉ ๊ฒฐ๊ณผ ์˜๋ฏธ
type ALL โ— ํ…Œ์ด๋ธ” ์ „์ฒด๋ฅผ ์Šค์บ”ํ•จ (ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”) → ์„ฑ๋Šฅ ๋งค์šฐ ์•ˆ ์ข‹์Œ
rows ์•ฝ 1,100๋งŒ ์ด๋งŒํผ์˜ ํ–‰์„ ํ›‘์–ด์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ
Extra Using where; Using filesort  
  • Using where: ์กฐ๊ฑด board_id = 1๋กœ ํ•„ํ„ฐ๋ง ์ค‘
  • Using filesort: ์ •๋ ฌ(created_at DESC) ์„ ์œ„ํ•ด ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ฆฌ์ง€ ๋ชปํ•˜๊ณ  ๋””์Šคํฌ์—์„œ ์ •๋ ฌ ์ˆ˜ํ–‰ํ•จ → ๋А๋ฆผ |

๐Ÿง  ์™œ ๋А๋ฆด๊นŒ?

  • ์ธ๋ฑ์Šค๊ฐ€ ์—†๊ฑฐ๋‚˜, ์ธ๋ฑ์Šค๋ฅผ ์ œ๋Œ€๋กœ ํ™œ์šฉํ•˜์ง€ ๋ชปํ•ด์„œ ALL ์Šค์บ” ๋ฐœ์ƒ
  • ORDER BY created_at DESC ๋•Œ๋ฌธ์— MySQL์ด ์ •๋ ฌ์„ ๋”ฐ๋กœ ์ˆ˜ํ–‰ํ•จ (filesort)
  • OFFSET 90๋„ ์„ฑ๋Šฅ์— ์•…์˜ํ–ฅ: ์•ž์˜ 90๊ฐœ๋Š” ๊ฑด๋„ˆ๋›ฐ๊ธฐ ์œ„ํ•ด ๋ฏธ๋ฆฌ ๋‹ค ์ฝ์–ด์•ผ ํ•จ

โœ… ๊ฐœ์„  ๋ฐฉํ–ฅ

  1. ๋ณตํ•ฉ ์ธ๋ฑ์Šค ์ถ”๊ฐ€
CREATE INDEX idx_board_created ON article(board_id, created_at DESC);
  1. WHERE ์ ˆ๊ณผ ์ •๋ ฌ ์กฐ๊ฑด์„ ๋ชจ๋‘ ํฌํ•จํ•œ ์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•จ
    • ๊ทธ๋ž˜์•ผ filesort ์—†์ด ์ธ๋ฑ์Šค๋งŒ์œผ๋กœ ์ •๋ ฌ ๊ฐ€๋Šฅ
  2. OFFSET ๋Œ€์‹  Cursor ๋ฐฉ์‹(๋ฌดํ•œ ์Šคํฌ๋กค) ๊ณ ๋ ค
    • ํŠนํžˆ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก OFFSET์€ ๋А๋ฆผ

โœ… ์ •๋ฆฌ ์š”์•ฝ

ํ•ญ๋ชฉ ์„ค๋ช…
type = ALL ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ „์ฒด ํ…Œ์ด๋ธ”์„ ์Šค์บ” ์ค‘
Using filesort ์ธ๋ฑ์Šค๋งŒ์œผ๋กœ ์ •๋ ฌํ•˜์ง€ ๋ชปํ•˜๊ณ , ๋””์Šคํฌ๋กœ ์ •๋ ฌํ•˜๋Š” ์ค‘
๊ฐœ์„  ํ•„์š” board_id + created_at ๋ณตํ•ฉ ์ธ๋ฑ์Šค ์ถ”๊ฐ€ ํ•„์š”
๋Œ€์•ˆ OFFSET ๋Œ€์‹  cursor ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง• ๊ณ ๋ ค ์‹œ ์„ฑ๋Šฅ ๊ฐœ์„  ๊ฐ€๋Šฅ

ํ•„์š”ํ•˜๋ฉด cursor ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง• ์ฟผ๋ฆฌ ์˜ˆ์‹œ, filesort ์—†์• ๋Š” ์ฟผ๋ฆฌ ์ตœ์ ํ™” ์˜ˆ์‹œ, MySQL ์‹คํ–‰ ๊ณ„ํš ๋” ์ž์„ธํ•œ ํ•ญ๋ชฉ ์„ค๋ช…๋„ ์ด์–ด์„œ ์•Œ๋ ค์ค„๊ฒŒ!


๐Ÿ“‘ RDB๋Š” ์ฃผ๋กœ B+ tree (Balanced Tree)

- ๋ฐ์ดํ„ฐ๊ฐ€ ์ •๋ ฌ๋œ ์ƒํƒœ๋กœ ์ €์žฅ

- ๊ฒ€์ƒ‰, ์‚ฝ์ž…, ์‚ญ์ œ ์—ฐ์‚ฐ์„ ๋กœ๊ทธ ์‹œ๊ฐ„์— ์ˆ˜ํ–‰ ๊ฐ€๋Šฅ

- ํŠธ๋ฆฌ ๊ตฌ์กฐ์—์„œ leaf node ๊ฐ„ ์—ฐ๊ฒฐ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฒ”์œ„ ๊ฒ€์ƒ‰ ํšจ์œจ์ 

create index idx_board_id_article_id on article(board_id asc, article_id desc);

 

- board_id ์˜ค๋ฆ„์ฐจ์ˆœ, article_id ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ

- ์ธ๋ฑ์Šค๋Š” ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•˜๋‹ค.

select * from article where board_id = 1 order by created_at desc limit 30 offset 90;
explain select * from article where board_id = 1 order by created_at desc limit 30 offset 90;
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys           | key                     | key_len | ref   | rows    | filtered | Extra |
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------+
|  1 | SIMPLE      | article | NULL       | ref  | idx_board_id_article_id | idx_board_id_article_id | 8       | const | 6274375 |   100.00 | NULL  |
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------+

 

๋ชจ๋“  ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋œ๊ฑด ์•„๋‹ˆ๋‹ค.

select * from article where board_id = 1 order by article_id desc limit 30 offset 1499970;
30 rows in set (3.23 sec)

 

์ฟผ๋ฆฌ ํ”Œ๋žœ์€ ๋™์ผํ•˜๊ณ  offset๋งŒ ๋ฐ”๊ผˆ์„ ๋ฟ์ธ๋ฐ ์™œ ์ด๋ ‡๊ฒŒ ์ฐจ์ด๊ฐ€ ๋‚˜์ง€?

์ด๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„  ์ธ๋ฑ์Šค์˜ ์ข…๋ฅ˜๋ฅผ ์•Œ ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

1. Clusterd Index

2. Secondary Index

 

๐Ÿ“Œ ์ธ๋ฑ์Šค์— ๋Œ€ํ•œ ์ดํ•ด – MySQL(InnoDB)

โœ… InnoDB๋ž€?

  • MySQL์˜ ๊ธฐ๋ณธ ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„
  • DB์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ์žฅ์น˜
  • InnoDB๋Š” **ํ…Œ์ด๋ธ”๋งˆ๋‹ค ์ž๋™์œผ๋กœ Clustered Index(ํด๋Ÿฌ์Šคํ„ฐํ˜• ์ธ๋ฑ์Šค)**๋ฅผ ์ƒ์„ฑํ•จ

๐Ÿงฑ Clustered Index๋ž€?

  • ํ…Œ์ด๋ธ”์˜ Primary Key๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ๋œ ์ธ๋ฑ์Šค
  • ๋ณดํ†ต Primary Key๊ฐ€ Clustered Index์˜ ๊ธฐ์ค€ ํ‚ค๊ฐ€ ๋จ
  • ์ด ์ธ๋ฑ์Šค์˜ leaf node๊ฐ€ ์‹ค์ œ ํ–‰(Row)์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ๋‹ด๊ณ  ์žˆ์Œ

๐Ÿ“Œ ์ •๋ฆฌํ•˜์ž๋ฉด:

Clustered Index๋Š” ์ •๋ ฌ๋œ ์ธ๋ฑ์Šค์ด๋ฉฐ,
leaf ๋…ธ๋“œ์— key-value์ฒ˜๋Ÿผ Primary Key = Row ๋ฐ์ดํ„ฐ ํ˜•ํƒœ๋กœ ์ €์žฅ๋œ๋‹ค.

 

๐Ÿ“Š ์˜ˆ์‹œ ๊ทธ๋ฆผ – Clustered Index ๊ตฌ์กฐ

์•„๋ž˜๋Š” Clustered Index๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ตฌ์กฐ๋„์•ผ:

                 [ Root Node ]
                    /    \
          [ id=1~3 ]    [ id=4~6 ]
            /   \           /   \
       [id=1] [id=2]   [id=4] [id=5]
       data1  data2    data4  data5
  • ์ •๋ ฌ ๊ธฐ์ค€: Primary Key
  • leaf node์— ์‹ค์ œ ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌ

๐Ÿ“ ์‹ค์ œ ํ…Œ์ด๋ธ” ์ ์šฉ ์˜ˆ: article ํ…Œ์ด๋ธ”

CREATE TABLE article (
  article_id BIGINT PRIMARY KEY,
  title VARCHAR(255),
  ...
) ENGINE=InnoDB;
  • article_id๋Š” Primary Key์ด๋ฏ€๋กœ,
    ์ž๋™์œผ๋กœ Clustered Index๋กœ ์ƒ์„ฑ๋จ

→ ์ฆ‰, ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์กฐ๊ฐ€ ๋จ:

Clustered Index: key = article_id
---------------------------------
[article_id=1] → article1 row data
[article_id=2] → article2 row data
[article_id=3] → article3 row data
...

 

Primary Key๋ฅผ ์กฐ๊ฑด์œผ๋กœ ํ•œ ์ฟผ๋ฆฌ๋Š” ์ด Clustered Index๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•ด์„œ ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ๊ฒ€์ƒ‰๋จ

 

โœ… ์š”์•ฝ

๊ฐœ๋… ์„ค๋ช…
Clustered Index InnoDB์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ…Œ์ด๋ธ”๋งˆ๋‹ค ์ƒ์„ฑ๋จ (๋ณดํ†ต PK ๊ธฐ์ค€)
leaf node ์‹ค์ œ ํ–‰(row) ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จ
์ •๋ ฌ ๊ธฐ์ค€ Primary Key์— ๋”ฐ๋ผ ์ž๋™ ์ •๋ ฌ
ํšจ์œจ์„ฑ PK๋กœ ์กฐํšŒ ์‹œ ๋งค์šฐ ๋น ๋ฅธ ์„ฑ๋Šฅ ์ œ๊ณต
์ฃผ์˜์  PK ์™ธ ๋‹ค๋ฅธ ์ปฌ๋Ÿผ ๊ธฐ์ค€ ์ธ๋ฑ์Šค๋Š” Secondary Index (→ row lookup ํ•„์š”)

ํ•„์š”ํ•˜๋ฉด ๋‹ค์Œ๋„ ์„ค๋ช…ํ•ด์ค„ ์ˆ˜ ์žˆ์–ด:

  • Clustered vs Non-clustered Index ์ฐจ์ด
  • Secondary Index์™€ Row Lookup ๊ณผ์ •
  • ์ธ๋ฑ์Šค ์„ค๊ณ„ ์‹œ ์ฃผ์˜ํ•  ์  (๋„ˆ๋ฌด ๋งŽ์œผ๋ฉด ์•ˆ ๋˜๋Š” ์ด์œ  ๋“ฑ)

์ด๋ฏธ์ง€ ํฌํ•จ๋œ HTML/Markdown ๋ฒ„์ „๋„ ์›ํ•˜๋ฉด ๋งŒ๋“ค์–ด์ค„๊ฒŒ!

 

์šฐ๋ฆฌ๊ฐ€ ์ƒ์„ฑํ•œ Index (board_id_article_id index) ๋Š” Secondary Index (Non-Clustered Index)๋‹ค.

Secondary Index ์˜ leaf node๋Š” ๋‹ค์Œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

1. ์ธ๋ฑ์Šค ์ปฌ๋Ÿผ ๋ฐ์ดํ„ฐ

2. ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ ํฌ์ธํ„ฐ

- ๋ฐ์ดํ„ฐ๋Š” Clustered Index๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

  > Clustered Index์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•œ ํฌ์ธํ„ฐ

  > Primary Key

 

๐Ÿ“Œ Secondary Index ์กฐํšŒ ์„ฑ๋Šฅ ์ €ํ•˜์˜ ์›์ธ ์ •๋ฆฌ

โœ… Clustered Index๋Š”?

  • InnoDB๋Š” **Primary Key๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ๋œ ์ธ๋ฑ์Šค(Tree ๊ตฌ์กฐ)**๋ฅผ ํ…Œ์ด๋ธ”๋งˆ๋‹ค ์ž๋™ ์ƒ์„ฑ
  • ์ด ์ธ๋ฑ์Šค๋Š” leaf ๋…ธ๋“œ์— ์‹ค์ œ row ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์–ด ๋ฐ”๋กœ ์กฐํšŒ ๊ฐ€๋Šฅํ•จ
  • ์ฆ‰, Primary Key๋กœ ์กฐํšŒํ•˜๋ฉด ์„ฑ๋Šฅ์ด ๋งค์šฐ ๋น ๋ฆ„

โœ… Secondary Index๋Š”?

  • Primary Key๊ฐ€ ์•„๋‹Œ ์ปฌ๋Ÿผ์— ์ƒ์„ฑํ•˜๋Š” ์ธ๋ฑ์Šค
  • leaf ๋…ธ๋“œ์—๋Š” row ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ํฌํ•จํ•˜์ง€ ์•Š๊ณ ,
    → ๋Œ€์‹  **"ํ•ด๋‹น row์˜ Primary Key ๊ฐ’(PK pointer)"**๋ฅผ ๊ฐ€์ง

๐Ÿ” Secondary Index๋ฅผ ์ด์šฉํ•œ ๋ฐ์ดํ„ฐ ์กฐํšŒ ๊ณผ์ •

  1. Secondary Index ํƒ์ƒ‰
    • ์›ํ•˜๋Š” ์กฐ๊ฑด(col=4)์„ ๊ฐ€์ง„ **id(PK)**๋ฅผ ์ฐพ์Œ
  2. **์ฐพ์€ PK(id)**๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ,
    → ๋‹ค์‹œ **Clustered Index(Primary Key Tree)**์— ์ ‘๊ทผํ•ด row๋ฅผ ์ฐพ์Œ

๐Ÿ‘‰ ์ฆ‰, ์ธ๋ฑ์Šค๋ฅผ ๋‘ ๋ฒˆ ํƒ€์•ผ ํ•œ๋‹ค!

 

๐Ÿ“‰ ์„ฑ๋Šฅ ์ด์Šˆ: ํŽ˜์ด์ง• ์ฟผ๋ฆฌ์—์„œ ๋А๋ ค์ง€๋Š” ์ด์œ 

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŽ˜์ด์ง• ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•  ๋•Œ:

SELECT * FROM article
WHERE board_id = 1
ORDER BY article_id DESC
LIMIT 30 OFFSET 1,499,970;

 

์‹คํ–‰ ํ๋ฆ„:

  1. (board_id, article_id) ์ธ๋ฑ์Šค์—์„œ **PK(article_id)**๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ํƒ์ƒ‰
  2. ๊ฐ article_id๋งˆ๋‹ค Clustered Index์—์„œ ์‹ค์ œ row data๋ฅผ ๋‹ค์‹œ ์กฐํšŒ
  3. ์ด๋ฅผ 1499970๋ฒˆ ๋ฐ˜๋ณตํ•ด์„œ skipํ•จ
  4. ๋งˆ์ง€๋ง‰์— LIMIT 30๊ฐœ๋งŒ ์ถ”์ถœ

โš ๏ธ ๊ฒฐ๊ณผ

  • ์ธ๋ฑ์Šค ํŠธ๋ฆฌ๋ฅผ 2๋ฒˆ ํƒ์ƒ‰ํ•˜๋ฉด์„œ,
  • 1,499,970๊ฐœ์˜ row๋ฅผ ์Šค์บ” ํ›„ 30๊ฐœ๋งŒ ์‚ฌ์šฉ
  • → ์„ฑ๋Šฅ ์ตœ์•… (๋А๋ ค์ง)

 

Q: ๋‘˜๋‹ค offset 1, offset 2, offset 3, ... offset 1499970 ํ•˜๋Š”๊ฑด ๋˜‘๊ฐ™์ž–์•„ ์ฐจ์ด์ ์€ ํ•˜๋‚˜๋Š” secondary index๋งŒ ํƒ„๋‹ค๋Š”๊ฑฐ๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” secondary index → clustered index ๋ฅผ ํƒ„๋‹ค๋Š”๊ฑฐ๊ณ  ๊ทผ๋ฐ ์ด๋ ‡๊ฒŒ ์‹œ๊ฐ„์ฐจ์ด๊ฐ€ ๋งŽ์ด๋‚˜?

๊ฑฐ์˜ 20๋ฐฐ ๋‚˜๋„ค ์™œ์ง€ ๋‚ด ์ƒ๊ฐ์—๋Š” logN * 1499970 vs logN+logM*1499970 ์ธ๋ฐ ๋งž๋‚˜?

 

์ด ๊ด€์ฐฐ์€ ์•„์ฃผ ์˜ˆ๋ฆฌํ•˜๊ณ  ์ •ํ™•ํ•œ ๋ฐฉํ–ฅ์œผ๋กœ ๊ฐ€๊ณ  ์žˆ์–ด์š”.
๋งž์•„์š”, ๋‘ ์ฟผ๋ฆฌ ๋‹ค offset 1499970๊นŒ์ง€ ์ผ์ผ์ด ์Šค์บ”ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ์„ฑ๋Šฅ ์ฐจ์ด๊ฐ€ **20๋ฐฐ ์ด์ƒ ๋‚˜๋Š” ์ง„์งœ ์ด์œ ๋Š” "๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ฒฝ๋กœ์˜ I/O ๋น„์šฉ ์ฐจ์ด"์ž…๋‹ˆ๋‹ค.

 

โœ… ํ•ต์‹ฌ ์ฐจ์ด: ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ฒฝ๋กœ์˜ ๋ฌด๊ฒŒ

ํ•ญ๋ชฉ SELECT board_id, article_id SELECT *
์ธ๋ฑ์Šค๋งŒ์œผ๋กœ ๊ฒฐ๊ณผ ๋„์ถœ ๊ฐ€๋Šฅ โœ… (covering index: ์ธ๋ฑ์Šค ๋ ˆ๋ฒจ์—์„œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ์กด์žฌ) โŒ (์ธ๋ฑ์Šค → PK ๊ฐ’ → ์‹ค์ œ row ๋กœ ์ด๋™ ํ•„์š”)
์Šค์บ” ์‹œ ํ•„์š”ํ•œ I/O ์ธ๋ฑ์Šค page๋งŒ ์Šค์บ” (๊ฐ€๋ณ๊ณ  ๋น ๋ฆ„) ๋งค row๋งˆ๋‹ค table row ์ ‘๊ทผ (๋ฌด๊ฒ๊ณ  ๋А๋ฆผ)
MySQL ์ ‘๊ทผ ๊ณผ์ • 1๋‹จ๊ณ„ (index๋งŒ) 2๋‹จ๊ณ„ (index → clustered)
I/O cost (rough scale) O(logN) O(logN + logM) or O(logN) + disk seek

 

๐Ÿ“‰ ๋””์Šคํฌ ์ ‘๊ทผ ๋น„์šฉ ์˜ˆ์‹œ

 

๊ฐ row์— ๋Œ€ํ•ด:

  • SELECT board_id, article_id๋Š” ์ธ๋ฑ์Šค page์—์„œ linearly scan
  • SELECT *๋Š” ์ธ๋ฑ์Šค → PK → row ์œ„์น˜๋กœ ๊ฐ€์•ผ ํ•˜๋ฏ€๋กœ random disk I/O ๋ฐœ์ƒ
    (ํŠนํžˆ InnoDB์—์„œ clustered index๋Š” ๋ฐ์ดํ„ฐ ์ž์ฒด๋‹ˆ๊นŒ ๋””์Šคํฌ ํƒ์ƒ‰ ๋งŽ์Œ)

์ฆ‰, 149๋งŒ ๋ฒˆ * (๋””์Šคํฌ ํƒ์ƒ‰ + I/O)๊ฐ€ ์ถ”๊ฐ€๋˜๋Š” ๊ฑฐ์˜ˆ์š”.

 

๐Ÿ“ ์‹œ๊ฐ„๋ณต์žก๋„๋กœ ๋น„์œ ํ•˜์ž๋ฉด?

๋„ค ๋ง์ฒ˜๋Ÿผ:

  • Covering index:
    O(logN) (B+ํŠธ๋ฆฌ ์ธ๋ฑ์Šค ์Šค์บ”๋งŒ)
  • Secondary index → PK:
    O(logN) + O(logM) + random I/O

→ ๊ทธ๋Ÿฐ๋ฐ ์‹ค์ œ ์‹œ๊ฐ„ ์ฐจ๋Š” CPU ์—ฐ์‚ฐ๋Ÿ‰๋ณด๋‹ค ๋””์Šคํฌ I/O ํŒจํ„ด์— ์˜ํ•ด ์ขŒ์šฐ๋ฉ๋‹ˆ๋‹ค.

 

๐Ÿง  ์‹ค๋ฌด ๊ฐ๊ฐ์ ์œผ๋กœ ํ‘œํ˜„ํ•˜์ž๋ฉด?

  • Covering index:
    ์ฑ… ๋ชฉ์ฐจ๋งŒ ํ›‘๋Š” ๊ฒƒ
  • Secondary index + PK:
    ๋ชฉ์ฐจ ๋ณด๊ณ  ๋งค๋ฒˆ ์ฑ… ๋ณธ๋ฌธ์œผ๋กœ ๊ฐ€์„œ ๋‚ด์šฉ๊นŒ์ง€ ์ฝ๋Š” ๊ฒƒ

→ ๊ทธ๊ฒŒ ์ˆ˜๋ฐฑ๋งŒ ๋ฒˆ ๋ฐ˜๋ณต๋˜๋ฉด ๋‹น์—ฐํžˆ ํ˜„์‹ค ์‹œ๊ฐ„์€ 20๋ฐฐ ์ด์ƒ ์ฐจ์ด ๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

โœ… ๊ทธ๋ž˜์„œ ์‹ค๋ฌด ํŒ

  • offset์ด ํฌ๋ฉด ์ ˆ๋Œ€ SELECT * ํ•˜์ง€ ๋ง ๊ฒƒ
  • preview์šฉ ์ฟผ๋ฆฌ๋Š” covering index ํ™œ์šฉ
  • ์ „์ฒด row๊ฐ€ ํ•„์š”ํ•˜๋ฉด Seek ๋ฐฉ์‹์œผ๋กœ pagination ๊ตฌํ˜„

 

โœ… ์š”์•ฝ ํ•œ ์ค„

Secondary Index๋Š” ๋ฐ์ดํ„ฐ ์กฐํšŒ ์‹œ Clustered Index๋ฅผ ๋‹ค์‹œ ํ•œ๋ฒˆ ๊ฑฐ์น˜๊ธฐ ๋•Œ๋ฌธ์—,
OFFSET์ด ํด์ˆ˜๋ก "๋‘ ๋ฒˆ ํƒ€๋Š” ๋น„์šฉ"์ด ๋ˆ„์ ๋˜์–ด ๋А๋ ค์ง„๋‹ค.

๋ฐ์ดํ„ฐ๋Š” offset 1,499,970๋ถ€ํ„ฐ 30๊ฐœ๋งŒ ํ•„์š”ํ•˜๋‹ค.

๊ทธ๋Ÿฐ๋ฐ offset 1,4999,970์„ ๋งŒ๋‚  ๋•Œ ๊นŒ์ง€ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค. (Secondary Index → Clustered Index * 1,499,970)

์ด๋ ‡๊ฒŒ ๋น„ํšจ์œจ์ ์ด๊ณ  ๋ฌด์˜๋ฏธํ•œ ๊ณผ์ •์„ ์ƒ๋žตํ•ด๋ณด์ž.

 

์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  Secondary Index๋Š” board_id ์™€ article_id๋ฅผ ํฌํ•จํ•œ๋‹ค.

Secondary Index์—์„œ ํ•„์š”ํ•œ 30๊ฑด์— ๋Œ€ํ•ด์„œ (1,499,971 ~ 1,500,000) article_id ๋งŒ ๋จผ์ € ์ถ”์ถœํ•˜๊ณ ,

๊ทธ 30๊ฑด์— ๋Œ€ํ•ด์„œ๋งŒ Clustered Index์— ์ ‘๊ทผํ•˜๋ฉด ์ถฉ๋ถ„ํ•˜์ง€ ์•Š๋‚˜?

article_id๋Š” Clustered Index์— ์ ‘๊ทผํ•˜์ง€ ์•Š์•„๋„ ์ถฉ๋ถ„ํžˆ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š” ์ •๋ณด์ผ์ง€ ๋ชจ๋ฅธ๋‹ค.

Secondary Index

select 
  board_id, 
  article_id 
from article 
where board_id = 1 
order by article_id desc 
limit 30 offset 1499970;
30 rows in set (0.37 sec)
explain
select 
  board_id, 
  article_id 
from article 
where board_id = 1 
order by article_id desc 
limit 30 offset 1499970;
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys           | key                     | key_len | ref   | rows    | filtered | Extra       |
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------------+
|  1 | SIMPLE      | article | NULL       | ref  | idx_board_id_article_id | idx_board_id_article_id | 8       | const | 6274375 |   100.00 | Using index |
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------------+

 

Query Plan์„ ์‚ดํŽด๋ณด์ž

์ธ๋ฑ์Šค๋Š” ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜์—ˆ์œผ๋‚˜, Extra=Using index๊ฐ€ ์ถ”๊ฐ€๋๋‹ค.

์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ–ˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค.

 

[๋น„๊ต๊ตฐ]

explain
select 
  *
from article 
where board_id = 1 
order by article_id desc 
limit 30 offset 1499970;
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys           | key                     | key_len | ref   | rows    | filtered | Extra |
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------+
|  1 | SIMPLE      | article | NULL       | ref  | idx_board_id_article_id | idx_board_id_article_id | 8       | const | 6274375 |   100.00 | NULL  |
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------+

 

์ด๋ ‡๊ฒŒ ์ธ๋ฑ์Šค์˜ ๋ฐ์ดํ„ฐ๋งŒ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์„ Covering Index ๋ผ๊ณ  ํ•จ

๏นก Covering Index๋ž€ ์ฟผ๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ธ๋ฑ์Šค๋งŒ ๋ณด๊ณ ๋„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ

Clustered Index๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ๋ฐ”๋กœ 1499970๊นŒ์ง€ ๋‹ฌ๋ ธ๋‹ค.

 

์ด์ œ ์ถ”์ถœ๋œ 30๊ฑด์— ๋Œ€ํ•ด์„œ๋งŒ Clustered Index์— ์ ‘๊ทผํ•˜๋ฉด ๋œ๋‹ค.

30๊ฑด์˜ article_id๋ฅผ sub query์˜ ๊ฒฐ๊ณผ๋กœ ๋งŒ๋“ค๊ณ , article ํ…Œ์ด๋ธ”๊ณผ join ํ•˜์ž

select *
from (
  select 
    article_id
  from article
  where board_id = 1
  order by article_id desc
  limit 30 offset 1499970
) t1
left join article t2
on t1.article_id = t2.article_id
explain
select *
from (
  select 
    article_id
  from article
  where board_id = 1
  order by article_id desc
  limit 30 offset 1499970
) t1
left join article t2
on t1.article_id = t2.article_id
+----+-------------+------------+------------+--------+-------------------------+-------------------------+---------+---------------+---------+----------+-------------+
| id | select_type | table      | partitions | type   | possible_keys           | key                     | key_len | ref           | rows    | filtered | Extra       |
+----+-------------+------------+------------+--------+-------------------------+-------------------------+---------+---------------+---------+----------+-------------+
|  1 | PRIMARY     | <derived2> | NULL       | ALL    | NULL                    | NULL                    | NULL    | NULL          | 1500000 |   100.00 | NULL        |
|  1 | PRIMARY     | t2         | NULL       | eq_ref | PRIMARY                 | PRIMARY                 | 8       | t1.article_id |       1 |   100.00 | NULL        |
|  2 | DERIVED     | article    | NULL       | ref    | idx_board_id_article_id | idx_board_id_article_id | 8       | const         | 6274375 |   100.00 | Using index |
+----+-------------+------------+------------+--------+-------------------------+-------------------------+---------+---------------+---------+----------+-------------+

 

article_id ์ถ”์ถœ์„ ์œ„ํ•œ sub query ์ƒ์„ฑ ๊ณผ์ •์—์„œ ํŒŒ์ƒ ํ…Œ์ด๋ธ”์ด ์ƒ๊ธฐ์ง€๋งŒ (DERIVED),

์ด ๊ณผ์ •์—์„œ Covering Index๊ฐ€ ์‚ฌ์šฉ๋˜์—ˆ๋‹ค.

์ž‘์€ ๊ทœ๋ชจ์˜ ํŒŒ์ƒ ํ…Œ์ด๋ธ”๊ณผ joinํ•˜์—ฌ 30๊ฑด์— ๋Œ€ํ•ด์„œ๋งŒ Clustered Index(PRIMARY)์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

 

์ด์ œ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋œ๊ฑธ๊นŒ? ์ด์   50,000๋ฒˆ ํŽ˜์ด์ง€๊ฐ€ ์•„๋‹ˆ๋ผ 300,000๋ฒˆ ํŽ˜์ด์ง€๋ฅผ ์กฐํšŒํ•ด๋ณด์ž

select *
from (
  select 
    article_id
  from article
  where board_id = 1
  order by article_id desc
  limit 30 offset 8999970
) t1
left join article t2
on t1.article_id = t2.article_id
30 rows in set (1.32 sec)

 

์‚ด์ง ๋А๋ฆฐ๋ฐ? 1์ดˆ → ๋’ค๋กœ ๊ฐˆ์ˆ˜๋ก ๋А๋ ค์ง€๋Š” ๋ฌธ์ œ๋Š” ์—ฌ์ „ํ•œ ๊ฒƒ์ด๋‹ค.

 

์‚ฌ์‹ค ๋™์ž‘๊ณผ์ •์„ ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋‹น์—ฐํ•œ ๊ฒƒ

article_id ์ถ”์ถœ์„ ์œ„ํ•ด Secondary Index๋งŒ ํƒ„๋‹ค๊ณ  ํ•ด๋„ offset(89,999,970)๋งŒํผ Index Scan์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ.

 

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€?

 

๐Ÿ“˜ ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก ์กฐํšŒ – ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ

โœ… ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ ๋” ๋ถ„๋ฆฌํ•œ๋‹ค

  • ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฒŒ์‹œ๊ธ€์„ 1๋…„ ๋‹จ์œ„๋กœ ํ…Œ์ด๋ธ” ๋ถ„๋ฆฌํ•œ๋‹ค.
    • ๊ฐœ๋ณ„ ํ…Œ์ด๋ธ”์˜ ํฌ๊ธฐ๋ฅผ ์ž‘๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
    • ๊ฐ ๋‹จ์œ„(1๋…„)์— ๋Œ€ํ•ด ์ „์ฒด ๊ฒŒ์‹œ๊ธ€ ์ˆ˜๋ฅผ ๋”ฐ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

โœ… offset์„ ํŽ˜์ด์ง€ ๋‹จ์œ„๊ฐ€ ์•„๋‹Œ ๊ฒŒ์‹œ๊ธ€ ์ˆ˜ ๋‹จ์œ„๋กœ skip

  • offset์€ ๋‹จ์ˆœํžˆ ์ธ๋ฑ์Šค ํŽ˜์ด์ง€๋ฅผ ๋„˜๊ธฐ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š” ๊ฒŒ์‹œ๊ธ€ ๊ฐœ์ˆ˜ ๋‹จ์œ„๋กœ skipํ•œ๋‹ค.
  • ์˜ˆ์‹œ:
    • offset์ด 1๋…„๊ฐ„ ์ž‘์„ฑ๋œ ๊ฒŒ์‹œ๊ธ€ ์ˆ˜๋ณด๋‹ค ํฌ๋ฉด, ํ•ด๋‹น ๋…„๋„์˜ ๊ฒŒ์‹œ๊ธ€ ์ „์ฒด๋ฅผ skip
    • ์ฆ‰, ๋” ํฐ ๋‹จ์œ„(์˜ˆ: ์—ฐ๋„๋ณ„ ํ…Œ์ด๋ธ”)๋กœ skip์„ ์ˆ˜ํ–‰
  • ์ด๋ฅผ ์œ„ํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ง์ ‘ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

๐Ÿ“˜ ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก ์กฐํšŒ – ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ (2)

โ“ 300,000๋ฒˆ ํŽ˜์ด์ง€๋ฅผ ์กฐํšŒํ•˜๋Š” ์‚ฌ์šฉ์ž๋Š” ์ •์ƒ์ผ๊นŒ?

  • ์ด๋Š” ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘์„ ๋ชฉ์ ์œผ๋กœ ํ•˜๋Š” ์–ด๋ทฐ์ €์ผ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค.

๐Ÿ›  ์ •์ฑ…์œผ๋กœ ํ•ด๊ฒฐํ•˜๊ธฐ

  • ์˜ˆ: ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก ์กฐํšŒ๋Š” ์ตœ๋Œ€ 10,000 ํŽ˜์ด์ง€๊นŒ์ง€๋งŒ ํ—ˆ์šฉ
  • ๋˜๋Š” ์‹œ๊ฐ„ ๋ฒ”์œ„ ํ˜น์€ ๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ ๊ธฐ๋ฐ˜ ์กฐํšŒ ๊ธฐ๋Šฅ ์ œ๊ณต
    • ์ž‘์€ ๋ฐ์ดํ„ฐ ๋ฒ”์œ„ ์•ˆ์—์„œ๋งŒ ํŽ˜์ด์ง•์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ์œ ๋„

๐Ÿ“˜ ๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก ์กฐํšŒ – ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ (3)

๐Ÿ” ๋ฌดํ•œ ์Šคํฌ๋กค

  • ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐฉ์‹์€ ๋’ท ํŽ˜์ด์ง€๋กœ ๊ฐˆ์ˆ˜๋ก ๋А๋ ค์งˆ ์ˆ˜๋ฐ–์— ์—†์Œ
    • OFFSET ๋ฐฉ์‹์€ ์ด์ „ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋ถ€ ์Šค์บ”ํ•˜๊ธฐ ๋•Œ๋ฌธ
  • ํ•˜์ง€๋งŒ ๋ฌดํ•œ ์Šคํฌ๋กค์€ ์–ด๋А ์œ„์น˜๋“  ์ผ์ •ํ•œ ์†๋„๋กœ ์กฐํšŒ ๊ฐ€๋Šฅ
    • ์ด๊ฑด OFFSET ๋Œ€์‹  WHERE id < ? ORDER BY id DESC LIMIT ? ๊ฐ™์€ ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง• ๋ฐฉ์‹ ๋•๋ถ„
  • ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐฉ์‹์— ๋Œ€ํ•œ ์„ค๋ช…์„ ๋งˆ์นœ ํ›„, ๋ฌดํ•œ ์Šคํฌ๋กค ๋ฐฉ์‹์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณผ ์˜ˆ์ •
explain select count(*) from article where board_id = 1;
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys           | key                     | key_len | ref   | rows    | filtered | Extra       |
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------------+
|  1 | SIMPLE      | article | NULL       | ref  | idx_board_id_article_id | idx_board_id_article_id | 8       | const | 6274375 |   100.00 | Using index |
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------------+

 

์ „์ฒด ๊ฐœ์ˆ˜ ์กฐํšŒ๋Š” 1์ดˆ ์ด์ƒ ๊ฑธ๋ฆฐ๋‹ค. (Covering Index ์‚ฌ์šฉ๋์ง€๋งŒ 120๋งŒ ๊ฑด ์กฐํšŒํ•ด์•ผ ํ•ด์„œ)

 

๊ทผ๋ฐ ํŽ˜์ด์ง•์„ ์ƒ๊ฐํ•ด๋ณด๋ฉด 

โ—€๏ธŽ 1 2 3 4 5 6 7 8 9 10 โ–ถ๏ธŽ                          : 301๊ฐœ ๊ฒŒ์‹œ๋ฌผ์˜ ์œ ๋ฌด๋งŒ ์•Œ๋ฉด ๋œ๋‹ค.

โ—€๏ธŽ 11 12 13 14 15 16 17 18 19 20 โ–ถ๏ธŽ          : 601๊ฐœ ๊ฒŒ์‹œ๋ฌผ์˜ ์œ ๋ฌด๋งŒ ์•Œ๋ฉด ๋œ๋‹ค.

โ—€๏ธŽ 21 22 23 24 25 26 27 28 29 30 โ–ถ๏ธŽ     : 901๊ฐœ ๊ฒŒ์‹œ๋ฌผ์˜ ์œ ๋ฌด๋งŒ ์•Œ๋ฉด ๋œ๋‹ค.

 

ํ™”๋ฉด ๊ตฌํ˜„์„ ์œ„ํ•ด ๊ตณ์ด ๋ชจ๋“  ๊ฒŒ์‹œ๊ธ€์„ ์กฐํšŒํ•  ํ•„์š”๋Š” ์—†๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ํ˜„์žฌ ์ด์šฉ ์ค‘์ธ ํŽ˜์ด์ง€ ๊ธฐ์ค€์— ๋”ฐ๋ผ์„œ, ๊ฒŒ์‹œ๊ธ€ ๊ฐœ์ˆ˜์˜ ์ผ๋ถ€๋งŒ ํ™•์ธํ•˜๋ฉด ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

์ „์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ ์ผ๋ถ€์— ๋Œ€ํ•ด์„œ๋งŒ ์นด์šดํŠธ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํฐ ๋น„์šฉ์—†์ด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

 

[๊ณต์‹ํ™”]

- ํ˜„์žฌ ํŽ˜์ด์ง€ : n (n>0)

- ํŽ˜์ด์ง€ ๋‹น ๊ฒŒ์‹œ๊ธ€ ๊ฐœ์ˆ˜ : m

- ์ด๋™ ๊ฐ€๋Šฅํ•œ ํŽ˜์ด์ง€ ๊ฐœ์ˆ˜ : k

๏นก(n - 1) / k ์˜ ๋‚˜๋จธ์ง€๋Š” ๋ฒ„๋ฆผ

 

→ `((n - 1) / k + 1) * m * k + 1`


๐Ÿ“‘ ํŠธ๋žœ์žญ์…˜ & B+ Tree ์ฐธ๊ณ 

 

์‰ฌ์šด์ฝ”๋“œ

11๋…„์ฐจ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฐฐ์›Œ์„œ ๋‚จ์ฃผ๋ ค๊ณ  ๋งŒ๋“  ์ฑ„๋„์ด์—์š” ์•Œ๊ธฐ ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค ํ•จ๊ป˜ ์„ฑ์žฅํ–ˆ์œผ๋ฉด ์ข‹๊ฒ ์–ด์š” :) #์ปด๊ณต๋ง›์ง‘ #๋ฐฑ์—”๋“œ์ „๋ฌธ์ฑ„๋„

www.youtube.com


๐Ÿ“‘ Pageable ์‚ฌ์šฉํ•˜๋ฉด ์ตœ์ ํ™”๋œ ์ฟผ๋ฆฌ๊ฐ€ ๋งŒ๋“ค์–ด์ง€์ง€ ์•Š์•„์„œ nativeQuery = true๋กœ ์‚ฌ์šฉ?


๐Ÿ“‘ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ์ค‘๋ณต/๋ˆ„๋ฝ ๋  ์ˆ˜ ์žˆ๋‹ค.

์•ž์„œ ๋งŒ๋“  ์ธ๋ฑ์Šค ๋ฐ์ดํ„ฐ (board_id asc, article_id desc)

 

1๋ฒˆ ์‚ฌ์šฉ์ž๋Š” ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐฉ์‹์œผ๋กœ 1๋ฒˆ์งธ ์Šคํฌ๋กค์—์„œ ๊ฒŒ์‹œ๊ธ€ 3๊ฐœ๋ฅผ ์กฐํšŒ. (offset=0, limit=3)

์ด ์‹œ์ ์— 2๋ฒˆ ์‚ฌ์šฉ์ž์— ์˜ํ•ด ์‹ ๊ทœ ๊ฒŒ์‹œ๊ธ€(article_id=8) ์ถ”๊ฐ€

1๋ฒˆ ์‚ฌ์šฉ์ž๋Š” ์Šคํฌ๋กค์„ ๋‚ด๋ ค์„œ 2๋ฒˆ์งธ ์Šคํฌ๋กค์„ ์กฐํšŒ.

๊ฒŒ์‹œ๊ธ€์ด ๋ฐ€๋ ค์„œ article=5 ๊ฒŒ์‹œ๊ธ€์ด ์ค‘๋ณต ์กฐํšŒ๋œ๋‹ค.

 

๋‹ค์‹œ ์ดˆ๊ธฐ ์ƒํƒœ (์‚ฌ์šฉ์ž๊ฐ€ ์ฒซ๋ฒˆ์งธ ์Šคํฌ๋กค์„ ์กฐํšŒํ•˜๊ณ  ์žˆ๋‹ค.)

2๋ฒˆ ์‚ฌ์šฉ์ž๊ฐ€ article=2 ๊ฒŒ์‹œ๊ธ€์„ ์‚ญ์ œํ•œ๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ์Šคํฌ๋กค์„ ๋‚ด๋ ค 2๋ฒˆ ์Šคํฌ๋กค๋กœ ์ด๋™ํ•˜๋ฉด article=4๊ฒŒ์‹œ๊ธ€์„ ๋ˆ„๋ฝํ•œ ์ฑ„ article=3๋ถ€ํ„ฐ ์กฐํšŒํ•˜๊ฒŒ ๋œ๋‹ค.

์ฆ‰, ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ๋ฐฉ์‹์€ ๋ฌดํ•œ ์Šคํฌ๋กค์— ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค.

 

ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฌดํ•œ์Šคํฌ๋กค์— ์ ํ•ฉํ•œ ๋ฐฉ์‹์ด ํ•„์š”ํ•˜๋‹ค.

 

๋ฌดํ•œ์Šคํฌ๋กค์—์„œ๋Š” ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ถˆ๋Ÿฌ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ์ค€์ ์œผ๋กœ ์‚ผ์„ ์ˆ˜ ์žˆ๋‹ค.

์‚ฌ์šฉ์ž๋Š” ์ฒซ๋ฒˆ์งธ ์Šคํฌ๋กค์„ ์กฐํšŒํ•˜๊ณ , article=5๋ฅผ ๊ธฐ์ค€์ ์œผ๋กœ ๊ธฐ์–ตํ•œ๋‹ค.

 

์ด ์‹œ์ ์— ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์— ์˜ํ•ด article=8 ๊ฒŒ์‹œ๊ธ€์ด ์ถ”๊ฐ€๋˜๊ณ , ๊ธฐ์กด ์‚ฌ์šฉ์ž๋Š” ์Šคํฌ๋กค์„ ๋‚ด๋ ค์„œ 2๋ฒˆ์งธ ์Šคํฌ๋กค์„ ์กฐํšŒํ•œ๋‹ค.

์•„๊นŒ ๊ธฐ์–ตํ•œ article=5 ๋ฏธ๋งŒ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ฒŒ ๋œ๋‹ค. 

 

์ •ํ™•ํ•œ ๊ธฐ์ค€์ (board_id=1, article_id=5)์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ธ๋ฑ์Šค ํŠธ๋ฆฌ์—์„œ ๋กœ๊ทธ์‹œ๊ฐ„์— ๊ธฐ์ค€์ ์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

๏นก ๋กœ๊ทธ์‹œ๊ฐ„์ธ ์ด์œ ๋Š” B+Tree ๋ผ์„œ ์ด๋ถ„ํƒ์ƒ‰์ด๋ž‘ ๋น„์Šทํ•˜๊ฒŒ ํƒ์ƒ‰ํ•˜๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์—

๊ธฐ์ค€์ ์—์„œ ๋ถ€ํ„ฐ limit 3๊ฐœ๋ฅผ ์กฐํšŒํ•œ๋‹ค. ์ด๋ฒˆ์—๋Š” ๊ฒŒ์‹œ๊ธ€์˜ ์ค‘๋ณต์—†์ด ์กฐํšŒ๋  ์ˆ˜ ์žˆ๋‹ค.

์ดํ›„ article=2๋กœ ๊ธฐ์ค€์ ์„ ๋‹ค์‹œ ๊ธฐ์–ตํ•˜๊ฒŒ ๋œ๋‹ค.

 

select * 
from article
where board_id = 1
order by article_id desc
limit 30;

select * 
from article
where board_id = 1
and article_id < #{์ด์ „์— ์กฐํšŒํ•œ ๋งˆ์ง€๋ง‰ ๊ธฐ์ค€์  article_id}
order by article_id desc
limit 30;
explain select * from article where board_id = 1 order by article_id desc limit 30;
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys           | key                     | key_len | ref   | rows    | filtered | Extra |
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------+
|  1 | SIMPLE      | article | NULL       | ref  | idx_board_id_article_id | idx_board_id_article_id | 8       | const | 6274375 |   100.00 | NULL  |
+----+-------------+---------+------------+------+-------------------------+-------------------------+---------+-------+---------+----------+-------+

 

๊ธฐ์ค€์ ์„ O(logN) ์‹œ๊ฐ„์„ ํ†ตํ•ด ์ฐพ๊ธฐ ๋•Œ๋ฌธ์— ๋งˆ์ง€๋ง‰ํŽ˜์ด์ง€ ์กฐํšŒ์†๋„๋„ ๋™์ผํ•˜๋‹ค.

 

๊ธฐ๋Šฅ ๊ตฌํ˜„ ์ˆœ์„œ (๋ ˆํผ์ง€ํ† ๋ฆฌ → ๋ ˆํผ์ง€ํ† ๋ฆฌ ํ…Œ์ŠคํŠธ → ์„œ๋น„์Šค → ์ปจํŠธ๋กค๋Ÿฌ → API ํ…Œ์ŠคํŠธ)


๐Ÿ“‘ PK ์ƒ์„ฑ ์ „๋žต

1) DB auto_increment

2) unique String or int

3) unique sorted String

4) unique sorted int

 

1) DB auto_increment

๋ถ„์‚ฐ ๋ฐ์ดํ„ฐ ํ™˜๊ฒฝ (์ƒค๋“œ1, ์ƒค๋“œ2)

๏นก๋ถ„์‚ฐ ๋ฐ์ดํ„ฐ ํ™˜๊ฒฝ์—์„œ ์‹๋ณ„์ž๊ฐ€ ์ค‘๋ณต๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์‹๋ณ„์ž์˜ ์œ ์ผ์„ฑ์ด ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.

(์—ฌ๋Ÿฌ ์ƒค๋“œ์—์„œ ๋™์ผํ•œ PK๋ฅผ ๊ฐ€์ง€๋Š” ์ƒํ™ฉ)

๏นก ํด๋ผ์ด์–ธํŠธ ์ธก์— ๋…ธ์ถœํ•˜๋ฉด ๋ณด์•ˆ ๋ฌธ์ œ

๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜ ๋˜๋Š” ํŠน์ • ์‹œ์ ์˜ ์‹๋ณ„์ž ์˜ˆ์ธก

(๋ฐฉ๊ธˆ ๊ฐ€์ž…ํ–ˆ๋”๋‹ˆ user_id=1,000 ์ด๋ฉด 1,000๋ช…์˜ ์‚ฌ์šฉ์ž๊ฐ€ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค ์œ ์ถ” ๊ฐ€๋Šฅ)

๏นก๊ฐ„๋‹จํ•˜๋‹ค๋Š” ์žฅ์ 

- ๋ณด์•ˆ์ ์ธ ๋ฌธ์ œ๋ฅผ ํฌ๊ฒŒ ๊ณ ๋ คํ•˜์ง€ ์•Š๊ฑฐ๋‚˜

- ๋‹จ์ผ DB๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๋˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธต์—์„œ PK์˜ ์ค‘๋ณต์„ ์ง์ ‘ ๊ตฌ๋ถ„ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

 

๋ณด์•ˆ์ ์ธ ๋ฌธ์ œ๋งŒ ์—ผ๋ ค๋œ๋‹ค๋ฉด, PK๋Š” DB๋‚ด์—์„œ์˜ ์‹๋ณ„์ž๋กœ๋งŒ ์‚ฌ์šฉํ•˜๊ณ ,

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ณ„์ธต์—์„œ์˜ ์‹๋ณ„์ž๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋ณ„๋„์˜ ์œ ๋‹ˆํฌ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

- PK = id (DB auto_increment)

- unique index = article_id(UUID ๋“ฑ)

- Client๋Š” article_id๋งŒ ์‹๋ณ„์ž๋กœ์„œ ๋…ธ์ถœ ๋ฐ ์‚ฌ์šฉ

Clustered Index & Secondary Index

์šฐ๋ฆฌ๋Š” ์ด๋ฏธ Clustered Index ์™€ Secondary Index๋ฅผ ํ•™์Šตํ–ˆ๋‹ค.

 

PK ์ ‘๊ทผ → Key=Primary

์œ ๋‹ˆํฌ ์ธ๋ฑ์Šค ์ ‘๊ทผ → key=idx_article_id

๋ณ„๋„์˜ ์‹๋ณ„์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Secondary Index๋กœ ํฌ์ธํ„ฐ ์ฐพ์€ ํ›„, Clustered Index๋กœ ์ ‘๊ทผํ•˜๋ฏ€๋กœ, ์กฐํšŒ ๋น„์šฉ์ด ์ฆ๊ฐ€ํ•œ๋‹ค.