[Lecture] ์คํ๋ง๋ถํธ๋ก ์ง์ ๋ง๋ค๋ฉด์ ๋ฐฐ์ฐ๋ ๋๊ท๋ชจ ์์คํ ์ค๊ณ - (2)
๐ ํ์ด์ง์ฒ๋ฆฌ์ ๋ฌดํ์คํฌ๋กค
๐ ๋๊ท๋ชจ ๊ฒ์๊ธ ๋ชฉ๋ก ์กฐํ๋ ์ ๋ณต์กํ ๊น?
- ๋ชจ๋ ๊ฒ์๊ธ ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ์ ์กฐํํด์ ๋ณด์ฌ์ค ์๋ ์๋ค.
- ๋ฉ๋ชจ๋ฆฌ, ๋คํธ์ํฌ, ์์คํ ์ฑ๋ฅ ๋ฑ์ ์ ์ฝ ๋๋ฌธ์ด๋ค.
- ๋ฐ๋ผ์ ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ํ์ด์ง ์ฒ๋ฆฌ๊ฐ ํ์ํ๋ค.
โ ํ์ด์ง์ ์ ๊ผญ ํด์ผ ํ๋?
- ์๋ฒ์์ ๋ชจ๋ ๊ฒ์๊ธ ๋ฐ์ดํฐ๋ฅผ ํ๊บผ๋ฒ์ ๋ถ๋ฌ์ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ฆฌ๋ ๊ฒ์ ๋นํจ์จ์ ์ด๋ค.
- ๋์คํฌ์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ๋ก ์ ๋ถ ๋ถ๋ฌ์ค๋ ๊ฑด ๋๋ฆฌ๊ณ , ๋์คํฌ 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๊ฐ๋ฅผ ๋ณด์ฌ์ฃผ๋ ๊ตฌ์กฐ
โ ํ์ํ ์ ๋ณด
- N๋ฒ ํ์ด์ง์์ M๊ฐ์ ๊ฒ์๊ธ์ ๋ณด์ฌ์ค๋ค๋ ๊ธฐ์ค
- ์ ์ฒด ๊ฒ์๊ธ ์๋ฅผ ์์์ผ ํ์ด์ง ๋ฒํธ๋ฅผ ๊ณ์ฐํ ์ ์์
- ์: ํ์ด์ง๋น 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๊ฐ๋ ๊ฑด๋๋ฐ๊ธฐ ์ํด ๋ฏธ๋ฆฌ ๋ค ์ฝ์ด์ผ ํจ
โ ๊ฐ์ ๋ฐฉํฅ
- ๋ณตํฉ ์ธ๋ฑ์ค ์ถ๊ฐ
CREATE INDEX idx_board_created ON article(board_id, created_at DESC);
- WHERE ์ ๊ณผ ์ ๋ ฌ ์กฐ๊ฑด์ ๋ชจ๋ ํฌํจํ ์ธ๋ฑ์ค๋ฅผ ๋ง๋ค์ด์ผ ํจ
- ๊ทธ๋์ผ filesort ์์ด ์ธ๋ฑ์ค๋ง์ผ๋ก ์ ๋ ฌ ๊ฐ๋ฅ
- 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๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ์กฐํ ๊ณผ์
- Secondary Index ํ์
- ์ํ๋ ์กฐ๊ฑด(col=4)์ ๊ฐ์ง **id(PK)**๋ฅผ ์ฐพ์
- **์ฐพ์ 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;
์คํ ํ๋ฆ:
- (board_id, article_id) ์ธ๋ฑ์ค์์ **PK(article_id)**๋ฅผ ์์๋๋ก ํ์
- ๊ฐ article_id๋ง๋ค Clustered Index์์ ์ค์ row data๋ฅผ ๋ค์ ์กฐํ
- ์ด๋ฅผ 1499970๋ฒ ๋ฐ๋ณตํด์ skipํจ
- ๋ง์ง๋ง์ 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์ ์ ๊ทผํ์ง ์์๋ ์ถฉ๋ถํ ๊ฐ์ ธ์ฌ ์ ์๋ ์ ๋ณด์ผ์ง ๋ชจ๋ฅธ๋ค.
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๋ ์ฟผ๋ฆฌ๊ฐ ํ์ํ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์ธ๋ฑ์ค๋ง ๋ณด๊ณ ๋ ์ฒ๋ฆฌํ ์ ์๋ ๊ฒฝ์ฐ
์ด์ ์ถ์ถ๋ 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๋ก ์ฌ์ฉ?
๐ ํ์ด์ง ๋ฒํธ ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ๊ฐ ์ค๋ณต/๋๋ฝ ๋ ์ ์๋ค.
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
๏นก๋ถ์ฐ ๋ฐ์ดํฐ ํ๊ฒฝ์์ ์๋ณ์๊ฐ ์ค๋ณต๋ ์ ์๊ธฐ ๋๋ฌธ์, ์๋ณ์์ ์ ์ผ์ฑ์ด ๋ณด์ฅ๋์ง ์๋๋ค.
(์ฌ๋ฌ ์ค๋์์ ๋์ผํ 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๋ฅผ ํ์ตํ๋ค.
PK ์ ๊ทผ → Key=Primary
์ ๋ํฌ ์ธ๋ฑ์ค ์ ๊ทผ → key=idx_article_id
๋ณ๋์ ์๋ณ์๋ฅผ ์ฌ์ฉํ๋ฉด Secondary Index๋ก ํฌ์ธํฐ ์ฐพ์ ํ, Clustered Index๋ก ์ ๊ทผํ๋ฏ๋ก, ์กฐํ ๋น์ฉ์ด ์ฆ๊ฐํ๋ค.