Ver3.0 ๐ ์ธ๋ฑ์ค ์ต์ ํ์ ์ฟผ๋ฆฌ ์ฑ๋ฅ ๊ฐ์ ๋ฐฉ๋ฒ

๐ ์ธ๋ฑ์ค ์ต์ ํ์ ์ฟผ๋ฆฌ ์ฑ๋ฅ ๊ฐ์ ๋ฐฉ๋ฒ
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฑ๋ฅ์ ํญ๋ฐ์ ์ผ๋ก ๋์ด์ฌ๋ฆฌ๋ ์ค์ ๊ฐ์ด๋
์๋ ! ์ค๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ค๋ฃจ๋ ๊ฐ๋ฐ์๋ผ๋ฉด ๋๊ตฌ๋ ํ ๋ฒ์ฏค ๊ณ ๋ฏผํ๊ฒ ๋๋ ์ฃผ์ ๋ฅผ ๊ฐ์ง๊ณ ์์ด. ๋ฐ๋ก ์ธ๋ฑ์ค ์ต์ ํ์ ์ฟผ๋ฆฌ ์ฑ๋ฅ ๊ฐ์ ์ด์ผ. ๐
์ฒ์ ๊ฐ๋ฐ์ ์์ํ ๋๋ ๋ฐ์ดํฐ๊ฐ ๋ช ์ฒ ๊ฑด ์ ๋๋ผ ์ฟผ๋ฆฌ๊ฐ ๋น ๋ฅด๊ฒ ๋์๊ฐ์ง? ๊ทธ๋ฐ๋ฐ ์๋น์ค๊ฐ ์ปค์ง๊ณ ๋ฐ์ดํฐ๊ฐ ์๋ฐฑ๋ง, ์์ฒ๋ง ๊ฑด์ผ๋ก ๋์ด๋๋ฉด ๊ฐ์๊ธฐ ์ฟผ๋ฆฌ ํ๋ ์คํํ๋๋ฐ ๋ช ์ด์ฉ ๊ฑธ๋ฆฌ๋ ์ํฉ์ด ์๊ฒจ. ์ฌ์ฉ์๋ ๋ต๋ตํดํ๊ณ , ์๋ฒ๋ ๊ณผ๋ถํ์ ์๋ฌ๋ฆฌ๊ณ ... ์ด๋ฐ ์ ์ํ์ด ์์๋๋ ๊ฑฐ์ง. ๐ฅ
์ด๋ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ํต์ฌ ์ด์ ๊ฐ ๋ฐ๋ก ์ธ๋ฑ์ค์ผ. ์ธ๋ฑ์ค๋ฅผ ์ ๋๋ก ์ดํดํ๊ณ ํ์ฉํ๋ฉด ์ฟผ๋ฆฌ ์ฑ๋ฅ์ ์์ญ ๋ฐฐ, ์ฌ์ง์ด ์๋ฐฑ ๋ฐฐ๊น์ง ๊ฐ์ ํ ์ ์์ด. ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์๋ ์๋ง์ ์ฌ์ฉ์ ๋ฐ์ดํฐ์ ๊ฑฐ๋ ์ ๋ณด๋ฅผ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌํ๋ ค๋ฉด ์ธ๋ฑ์ค ์ต์ ํ๊ฐ ํ์์ ์ด์ง.
๊ทธ๋ผ ์ง๊ธ๋ถํฐ ์ธ๋ฑ์ค์ ๊ธฐ๋ณธ ๊ฐ๋ ๋ถํฐ ์ค์ ์ต์ ํ ๊ธฐ๋ฒ๊น์ง, ์น๊ตฌ์๊ฒ ์ค๋ช ํ๋ฏ ํธํ๊ฒ ํ์ด๋ณผ๊ฒ! ๐
๐ ์ธ๋ฑ์ค๋ ๋ฌด์์ธ๊ฐ?
์ธ๋ฑ์ค๋ฅผ ์ดํดํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ์ฑ ์ ์์ธ์ ๋ ์ฌ๋ฆฌ๋ ๊ฑฐ์ผ. ๋๊บผ์ด ๋ฐฑ๊ณผ์ฌ์ ์์ ํน์ ๋จ์ด๋ฅผ ์ฐพ๋๋ค๊ณ ์๊ฐํด๋ด. ์์ธ ์์ด ์ฒซ ํ์ด์ง๋ถํฐ ๋๊น์ง ๋๊ธฐ๋ฉด์ ์ฐพ์ผ๋ฉด ์ผ๋ง๋ ์ค๋ ๊ฑธ๋ฆด๊น? ๐ฐ
ํ์ง๋ง ๋ค์ชฝ์ ์๋ ์์ธ์ ๋ณด๋ฉด "๋ฐ์ดํฐ๋ฒ ์ด์ค โ 347ํ์ด์ง"์ฒ๋ผ ๋ฐ๋ก ์ฐพ์ ์ ์์ง. ์ธ๋ฑ์ค๋ ์ ํํ ๊ฐ์ ์๋ฆฌ์ผ. ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํน์ ๋ฐ์ดํฐ๋ฅผ ๋น ๋ฅด๊ฒ ์ฐพ๊ธฐ ์ํ ์ ๋ ฌ๋ ์ฐธ์กฐ ๊ตฌ์กฐ์ธ ๊ฑฐ์ง.
๐ฏ ์ธ๋ฑ์ค์ ํต์ฌ ๊ฐ๋
์ธ๋ฑ์ค๋ ํ ์ด๋ธ์ ํน์ ์ปฌ๋ผ ๊ฐ์ ์ ๋ ฌํด์ ์ ์ฅํ๊ณ , ๊ทธ ๊ฐ์ด ์ค์ ๋ฐ์ดํฐ์ ์ด๋์ ์๋์ง ํฌ์ธํฐ๋ฅผ ํจ๊ป ๋ณด๊ดํด. ๊ทธ๋์ ๊ฒ์ํ ๋ ์ ์ฒด ํ ์ด๋ธ์ ๋ค์ง์ง ์๊ณ ์ธ๋ฑ์ค๋ง ๋น ๋ฅด๊ฒ ํ์ํ ํ, ํ์ํ ๋ฐ์ดํฐ์ ์์น๋ก ๋ฐ๋ก ์ ํํ ์ ์๋ ๊ฑฐ์ผ.
์๋ฅผ ๋ค์ด 100๋ง ๋ช ์ ํ์ ์ ๋ณด๊ฐ ์๋ ํ ์ด๋ธ์์ "ํ๊ธธ๋"์ด๋ผ๋ ์ด๋ฆ์ ์ฐพ๋๋ค๊ณ ํด๋ณด์. ์ธ๋ฑ์ค๊ฐ ์์ผ๋ฉด 100๋ง ๊ฐ ํ์ ํ๋์ฉ ๋ค ํ์ธํด์ผ ํด. ์ด๊ฑธ Full Table Scan(์ ์ฒด ํ ์ด๋ธ ์ค์บ)์ด๋ผ๊ณ ํ์ง.
ํ์ง๋ง ์ด๋ฆ ์ปฌ๋ผ์ ์ธ๋ฑ์ค๊ฐ ์๋ค๋ฉด? ์ธ๋ฑ์ค๋ ์ด๋ฏธ ์ด๋ฆ์์ผ๋ก ์ ๋ ฌ๋์ด ์๊ณ , B-Tree ๊ฐ์ ํจ์จ์ ์ธ ์๋ฃ๊ตฌ์กฐ๋ก ๊ตฌ์ฑ๋์ด ์์ด์ ๋ช ๋ฒ์ ๋น๊ต๋ง์ผ๋ก "ํ๊ธธ๋"์ ์ฐพ์ ์ ์์ด. ๋ง์น ์ด์ง ํ์์ฒ๋ผ ๋ง์ด์ผ! ๐ฏ
๐ณ ์ธ๋ฑ์ค์ ๋ด๋ถ ๊ตฌ์กฐ - B-Tree
๋๋ถ๋ถ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์ธ๋ฑ์ค๋ฅผ B-Tree(Balanced Tree) ๋๋ B+Tree ๊ตฌ์กฐ๋ก ๊ตฌํํด. ์ด ๊ตฌ์กฐ๊ฐ ์ ์ค์ํ์ง ์์๋ณด์.
๐ก B-Tree์ ํน์ง
B-Tree๋ ๊ท ํ ์กํ ํธ๋ฆฌ ๊ตฌ์กฐ๋ก, ๋ชจ๋ ๋ฆฌํ ๋ ธ๋(๋ง๋จ ๋ ธ๋)๊ฐ ๊ฐ์ ๊น์ด์ ์์ด. ์ด๊ฒ ๋ฌด์จ ์๋ฏธ๋๋ฉด, ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ์ฐพ๋ ํญ์ ๋น์ทํ ์๊ฐ์ด ๊ฑธ๋ฆฐ๋ค๋ ๊ฑฐ์ผ. ์ต์ ์ ๊ฒฝ์ฐ์๋ ์ฑ๋ฅ์ด ๋ณด์ฅ๋๋ ๊ฑฐ์ง! โจ
B-Tree๋ ๋ค์๊ณผ ๊ฐ์ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ์ ธ:
1. ๋ฃจํธ ๋
ธ๋(Root Node)
ํธ๋ฆฌ์ ์ต์๋จ์ ์๋ ๋
ธ๋์ผ. ์ฌ๊ธฐ์๋ถํฐ ๊ฒ์์ด ์์๋์ง.
2. ๋ธ๋์น ๋
ธ๋(Branch Node)
์ค๊ฐ ๊ณ์ธต์ ๋
ธ๋๋ค์ด์ผ. ๋ฐ์ดํฐ๋ฅผ ๋ ์ธ๋ฐํ๊ฒ ๋ถ๋ฅํด์ ์๋๋ก ์๋ดํ๋ ์ญํ ์ ํด.
3. ๋ฆฌํ ๋
ธ๋(Leaf Node)
์ค์ ์ธ๋ฑ์ค ํค ๊ฐ๊ณผ ๋ฐ์ดํฐ ์์น(ํฌ์ธํฐ)๊ฐ ์ ์ฅ๋๋ ๊ณณ์ด์ผ. ์ฌ๊ธฐ์ ์ต์ข
์ ์ผ๋ก ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ์ฐพ๊ฒ ๋ผ.
๐ ๊ฒ์ ๊ณผ์ ์์
100๋ง ๊ฑด์ ๋ฐ์ดํฐ๊ฐ ์๋ ํ ์ด๋ธ์์ ํน์ ๊ฐ์ ์ฐพ๋๋ค๊ณ ํด๋ณด์. B-Tree ์ธ๋ฑ์ค๊ฐ ์์ผ๋ฉด ๋๋ต 3~4๋ฒ์ ๋ ธ๋ ํ์๋ง์ผ๋ก ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ์ฐพ์ ์ ์์ด. ์๋ํ๋ฉด ๊ฐ ๋ ธ๋๊ฐ ์๋ฐฑ ๊ฐ์ ํค๋ฅผ ๊ฐ์ง ์ ์๊ณ , ํธ๋ฆฌ์ ๋์ด๊ฐ ๋งค์ฐ ๋ฎ๊ฒ ์ ์ง๋๊ธฐ ๋๋ฌธ์ด์ผ.
๊ณ์ฐํด๋ณด๋ฉด: logโโโ(1,000,000) โ 3๋จ๊ณ๋ฉด ์ถฉ๋ถํด! ๐ฒ
MySQL์ InnoDB ์์ง์ B+Tree๋ฅผ ์ฌ์ฉํ๋๋ฐ, ์ด๊ฑด B-Tree์ ๋ณํ์ด์ผ. B+Tree๋ ๋ชจ๋ ์ค์ ๋ฐ์ดํฐ๊ฐ ๋ฆฌํ ๋ ธ๋์๋ง ์๊ณ , ๋ฆฌํ ๋ ธ๋๋ผ๋ฆฌ ์ฐ๊ฒฐ๋์ด ์์ด์ ๋ฒ์ ๊ฒ์์ ํนํ ์ ๋ฆฌํด. ์๋ฅผ ๋ค์ด "2024๋ 1์ 1์ผ๋ถํฐ 12์ 31์ผ๊น์ง"๊ฐ์ ๋ฒ์ ์กฐ๊ฑด์ ์ฒ๋ฆฌํ ๋ ์์ฒญ ๋น ๋ฅด์ง! ๐
๐จ ์ธ๋ฑ์ค์ ์ข ๋ฅ
์ธ๋ฑ์ค์๋ ์ฌ๋ฌ ์ข ๋ฅ๊ฐ ์์ด. ์ํฉ์ ๋ฐ๋ผ ์ ์ ํ ์ธ๋ฑ์ค๋ฅผ ์ ํํ๋ ๊ฒ ์ค์ํ์ง. ํ๋์ฉ ์ดํด๋ณผ๊น? ๐
ํด๋ฌ์คํฐ๋ ์ธ๋ฑ์ค (Clustered Index)
ํด๋ฌ์คํฐ๋ ์ธ๋ฑ์ค๋ ํ ์ด๋ธ์ ์ค์ ๋ฐ์ดํฐ ์์ฒด๋ฅผ ์ ๋ ฌํด์ ์ ์ฅํ๋ ์ธ๋ฑ์ค์ผ. ์ฑ ์ผ๋ก ์น๋ฉด ํ์ด์ง ์์ฒด๊ฐ ์ด๋ฏธ ์์๋๋ก ์ ๋ ฌ๋์ด ์๋ ๊ฑฐ์ง.
ํน์ง:
โข ํ
์ด๋ธ๋น ํ๋๋ง ์์ฑ ๊ฐ๋ฅ (๋ฐ์ดํฐ๋ ํ ๊ฐ์ง ๋ฐฉ์์ผ๋ก๋ง ์ ๋ ฌ๋ ์ ์์ผ๋๊น)
โข Primary Key์ ์๋์ผ๋ก ์์ฑ๋จ
โข ๊ฒ์ ์๋๊ฐ ๋งค์ฐ ๋น ๋ฆ
โข ๋ฐ์ดํฐ ์ฝ์
/์์ /์ญ์ ์ ๋ฌผ๋ฆฌ์ ์ฌ์ ๋ ฌ์ด ํ์ํด์ ์ฝ๊ฐ ๋๋ฆด ์ ์์
๋ ผํด๋ฌ์คํฐ๋ ์ธ๋ฑ์ค (Non-Clustered Index)
๋ ผํด๋ฌ์คํฐ๋ ์ธ๋ฑ์ค๋ ๋ณ๋์ ๊ณต๊ฐ์ ์ธ๋ฑ์ค๋ฅผ ์์ฑํ๊ณ , ์ค์ ๋ฐ์ดํฐ ์์น๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ๋ฅผ ์ ์ฅํด. ์ฑ ์ ์์ธ ํ์ด์ง์ ๋๊ฐ์!
ํน์ง:
โข ํ
์ด๋ธ๋น ์ฌ๋ฌ ๊ฐ ์์ฑ ๊ฐ๋ฅ
โข ๊ฒ์ ์ ์ธ๋ฑ์ค๋ฅผ ๋จผ์ ์ฐพ๊ณ , ๊ทธ ๋ค์ ์ค์ ๋ฐ์ดํฐ๋ก ์ด๋ (2๋จ๊ณ)
โข ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์ ํด๋ฌ์คํฐ๋๋ณด๋ค ๋น ๋ฆ
โข ์ถ๊ฐ ์ ์ฅ ๊ณต๊ฐ ํ์
์ ๋ํฌ ์ธ๋ฑ์ค (Unique Index)
์ ๋ํฌ ์ธ๋ฑ์ค๋ ์ค๋ณต๋ ๊ฐ์ ํ์ฉํ์ง ์๋ ์ธ๋ฑ์ค์ผ. ์ด๋ฉ์ผ์ด๋ ์ฃผ๋ฏผ๋ฑ๋ก๋ฒํธ์ฒ๋ผ ๊ณ ์ ํด์ผ ํ๋ ๊ฐ์ ์ฌ์ฉํ์ง. ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ๋ฉด์ ๋์์ ๊ฒ์ ์ฑ๋ฅ๋ ํฅ์์ํฌ ์ ์์ด! ๐ฏ
๋ณตํฉ ์ธ๋ฑ์ค (Composite Index)
๐ก ๋ณตํฉ ์ธ๋ฑ์ค์ ๋ง๋ฒ
๋ณตํฉ ์ธ๋ฑ์ค๋ ์ฌ๋ฌ ์ปฌ๋ผ์ ์กฐํฉํด์ ๋ง๋๋ ์ธ๋ฑ์ค์ผ. ์๋ฅผ ๋ค์ด (์ฑ, ์ด๋ฆ) ์์๋ก ๋ณตํฉ ์ธ๋ฑ์ค๋ฅผ ๋ง๋ค๋ฉด, "๊น์จ ์ค์์ ์ฒ ์"๋ฅผ ์ฐพ๋ ์ฟผ๋ฆฌ๊ฐ ์์ฒญ ๋น ๋ฅด๊ฒ ์คํ๋ผ.
์ค์ํ ์ : ์ปฌ๋ผ์ ์์๊ฐ ๋งค์ฐ ์ค์ํด! (A, B, C) ์์๋ก ๋ง๋ ์ธ๋ฑ์ค๋ A๋ก ๊ฒ์, A+B๋ก ๊ฒ์, A+B+C๋ก ๊ฒ์ํ ๋๋ ํจ๊ณผ์ ์ด์ง๋ง, B๋ง์ผ๋ก ๊ฒ์ํ๊ฑฐ๋ C๋ง์ผ๋ก ๊ฒ์ํ ๋๋ ์ธ๋ฑ์ค๋ฅผ ์ ๋๋ก ํ์ฉํ์ง ๋ชปํด. ์ด๊ฑธ ์ธ๋ฑ์ค์ ์ผ์ชฝ ์ฐ์ ์์น์ด๋ผ๊ณ ํด! ๐
์ปค๋ฒ๋ง ์ธ๋ฑ์ค (Covering Index)
์ปค๋ฒ๋ง ์ธ๋ฑ์ค๋ ์ฟผ๋ฆฌ์์ ํ์ํ ๋ชจ๋ ์ปฌ๋ผ์ด ์ธ๋ฑ์ค์ ํฌํจ๋์ด ์์ด์, ์ค์ ํ ์ด๋ธ์ ์ ๊ทผํ์ง ์๊ณ ์ธ๋ฑ์ค๋ง์ผ๋ก ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์๋ ๊ฒฝ์ฐ๋ฅผ ๋งํด. ์ด๊ฑด ์ ๋ง ์ต๊ณ ์ ์ฑ๋ฅ์ ๋ด๋ ๋ฐฉ๋ฒ์ด์ผ! ๐
-- ์์: (user_id, name, email) ๋ณตํฉ ์ธ๋ฑ์ค๊ฐ ์์ ๋
SELECT name, email FROM users WHERE user_id = 100;
-- ์ด ์ฟผ๋ฆฌ๋ ์ธ๋ฑ์ค๋ง ์ฝ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์์ (์ปค๋ฒ๋ง ์ธ๋ฑ์ค)
-- ์ค์ ํ
์ด๋ธ ์ ๊ทผ ์์ด ์ด๊ณ ์ ์ฒ๋ฆฌ! โก
์ ๋ฌธ ๊ฒ์ ์ธ๋ฑ์ค (Full-Text Index)
์ ๋ฌธ ๊ฒ์ ์ธ๋ฑ์ค๋ ํ ์คํธ ๋ด์ฉ์ ๊ฒ์ํ ๋ ์ฌ์ฉํด. ๋ธ๋ก๊ทธ ๊ธ์ด๋ ์ํ ์ค๋ช ์ฒ๋ผ ๊ธด ํ ์คํธ์์ ํน์ ๋จ์ด๋ฅผ ์ฐพ์ ๋ ์ ์ฉํ์ง. ์ผ๋ฐ ์ธ๋ฑ์ค๋ก๋ LIKE '%๊ฒ์์ด%' ๊ฐ์ ํจํด ๋งค์นญ์ด ๋๋ฆฐ๋ฐ, ์ ๋ฌธ ๊ฒ์ ์ธ๋ฑ์ค๋ฅผ ์ฐ๋ฉด ํจ์ฌ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌํ ์ ์์ด! ๐
โก ์ธ๋ฑ์ค๊ฐ ์ฑ๋ฅ์ ํฅ์์ํค๋ ์๋ฆฌ
์ด์ ์ธ๋ฑ์ค๊ฐ ์ค์ ๋ก ์ด๋ป๊ฒ ์ฟผ๋ฆฌ ์ฑ๋ฅ์ ๊ฐ์ ํ๋์ง ๊ตฌ์ฒด์ ์ผ๋ก ์์๋ณด์. ์ซ์๋ก ๋ณด๋ฉด ๋ ์ค๊ฐ์ด ๋ ๊ฑฐ์ผ! ๐
โ ์ธ๋ฑ์ค ์์ ๋
Full Table Scan
โข ๋ชจ๋ ํ์ ์์ฐจ์ ์ผ๋ก ์ฝ์
โข 1,000,000๊ฑด โ 1,000,000๋ฒ ๋น๊ต
โข ์๊ฐ ๋ณต์ก๋: O(n)
โข ์์ ์๊ฐ: 10์ด
โ ์ธ๋ฑ์ค ์์ ๋
Index Seek
โข B-Tree ํ์
โข 1,000,000๊ฑด โ ์ฝ 20๋ฒ ๋น๊ต
โข ์๊ฐ ๋ณต์ก๋: O(log n)
โข ์์ ์๊ฐ: 0.01์ด
๐ ์ค์ ์ฑ๋ฅ ๊ฐ์ ์ฌ๋ก
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ์ฌ์ฉ์ ๊ฒ์ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค๊ณ ์๊ฐํด๋ด. 100๋ง ๋ช ์ ํ์ ์ค์์ ํน์ ์ฌ์ฉ์๋ฅผ ์ฐพ๋ ์ฟผ๋ฆฌ๊ฐ ์๋ค๋ฉด:
์ธ๋ฑ์ค ์ ์ฉ ์ : ํ๊ท 8์ด
์ธ๋ฑ์ค ์ ์ฉ ํ: ํ๊ท 0.005์ด
๊ฐ์ ์จ: 1,600๋ฐฐ! ๐ฑ
์ด ์ ๋๋ฉด ์ฌ์ฉ์ ๊ฒฝํ์ด ์์ ํ ๋ฌ๋ผ์ง์ง. ๋ต๋ตํ๊ฒ ๊ธฐ๋ค๋ฆฌ๋ ํ๋ฉด์ด ์ฆ์ ๋ํ๋๋ ๊ฑฐ์ผ!
์ธ๋ฑ์ค์ ์ฑ๋ฅ ํฅ์์ ํนํ ๋ค์๊ณผ ๊ฐ์ ์ํฉ์์ ๋๋๋ฌ์ ธ:
WHERE ์ ์กฐ๊ฑด ๊ฒ์
๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ด๊ณ ํํ ๊ฒฝ์ฐ์ผ. WHERE user_id = 123 ๊ฐ์ ์กฐ๊ฑด์ด ์์ ๋ user_id์ ์ธ๋ฑ์ค๊ฐ ์์ผ๋ฉด ๋ฐ๋ก ์ฐพ์ ์ ์์ง.
ORDER BY ์ ๋ ฌ
์ธ๋ฑ์ค๋ ์ด๋ฏธ ์ ๋ ฌ๋ ์ํ๋ก ์ ์ฅ๋์ด ์์ด์, ORDER BY ์ ์ ์ฌ์ฉํ ๋ ๋ณ๋์ ์ ๋ ฌ ์์
์์ด ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ์ ์์ด. ์ด๊ฑธ Using index๋ผ๊ณ ํ๋๋ฐ, ์คํ ๊ณํ์์ ์ด ๋ฌธ๊ตฌ๋ฅผ ๋ณด๋ฉด ์ต์ ํ๊ฐ ์ ๋ ๊ฑฐ์ผ! ๐
JOIN ์ฐ์ฐ
๋ ํ
์ด๋ธ์ ์กฐ์ธํ ๋ ์กฐ์ธ ํค์ ์ธ๋ฑ์ค๊ฐ ์์ผ๋ฉด ์ฑ๋ฅ์ด ๊ทน์ ์ผ๋ก ํฅ์๋ผ. ํนํ ๋์ฉ๋ ํ
์ด๋ธ๋ผ๋ฆฌ ์กฐ์ธํ ๋๋ ์ธ๋ฑ์ค๊ฐ ํ์์ผ.
GROUP BY ์ง๊ณ
๊ทธ๋ฃนํํ ์ปฌ๋ผ์ ์ธ๋ฑ์ค๊ฐ ์์ผ๋ฉด ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ์ ๋ ฌ๋ ์ํ๋ก ์ฝ์ ์ ์์ด์ ์ง๊ณ ์ฐ์ฐ์ด ํจ์ฌ ๋นจ๋ผ์ ธ.
๐ฏ ์ธ๋ฑ์ค ์์ฑ ์ ๋ต
์, ์ด์ ์ธ๋ฑ์ค๊ฐ ์ ์ค์ํ์ง ์์์ผ๋, ์ค์ ์์ ์ด๋ป๊ฒ ์ธ๋ฑ์ค๋ฅผ ๋ง๋ค์ด์ผ ํ๋์ง ์์๋ณด์. ๋ฌด์์ ๋ง์ด ๋ง๋ ๋ค๊ณ ์ข์ ๊ฒ ์๋์ผ! ๐ค
์ธ๋ฑ์ค๋ฅผ ๋ง๋ค์ด์ผ ํ๋ ์ปฌ๋ผ
โ ์ด๋ฐ ์ปฌ๋ผ์๋ ์ธ๋ฑ์ค๋ฅผ ๋ง๋ค์
1. WHERE ์ ์ ์์ฃผ ์ฌ์ฉ๋๋ ์ปฌ๋ผ
๊ฒ์ ์กฐ๊ฑด์ผ๋ก ์์ฃผ ์ฐ์ด๋ ์ปฌ๋ผ์ ๋น์ฐํ ์ธ๋ฑ์ค ํ๋ณด์ผ. ์ฌ์ฉ์ ID, ์ด๋ฉ์ผ, ์ ํ๋ฒํธ ๊ฐ์ ๊ฒ๋ค์ด์ง.
2. JOIN ์กฐ๊ฑด์ ์ฌ์ฉ๋๋ ์ปฌ๋ผ
์ธ๋ ํค(Foreign Key)๋ ๊ฑฐ์ ํ์๋ก ์ธ๋ฑ์ค๋ฅผ ๋ง๋ค์ด์ผ ํด. ์กฐ์ธ ์ฑ๋ฅ์ ์ง์ ์ ์ธ ์ํฅ์ ์ฃผ๊ฑฐ๋ .
3. ORDER BY, GROUP BY์ ์์ฃผ ์ฌ์ฉ๋๋ ์ปฌ๋ผ
์ ๋ ฌ์ด๋ ๊ทธ๋ฃนํ์ด ๋น๋ฒํ๋ค๋ฉด ์ธ๋ฑ์ค๋ก ์ฑ๋ฅ์ ํฌ๊ฒ ๊ฐ์ ํ ์ ์์ด.
4. ์นด๋๋๋ฆฌํฐ(Cardinality)๊ฐ ๋์ ์ปฌ๋ผ
์นด๋๋๋ฆฌํฐ๋ ์ปฌ๋ผ ๊ฐ์ ๊ณ ์ ํ ์ ๋๋ฅผ ๋งํด. ์๋ฅผ ๋ค์ด ์ฑ๋ณ(๋จ/์ฌ)์ ์นด๋๋๋ฆฌํฐ๊ฐ ๋ฎ๊ณ , ์ฌ์ฉ์ ID๋ ์นด๋๋๋ฆฌํฐ๊ฐ ๋์. ์นด๋๋๋ฆฌํฐ๊ฐ ๋์์๋ก ์ธ๋ฑ์ค ํจ๊ณผ๊ฐ ์ข์! ๐ฒ
์ธ๋ฑ์ค๋ฅผ ๋ง๋ค์ง ๋ง์์ผ ํ๋ ๊ฒฝ์ฐ
โ ๏ธ ์ด๋ฐ ๊ฒฝ์ฐ๋ ์ธ๋ฑ์ค๊ฐ ๋ ์ด ๋ ์ ์์ด
1. ๋ฐ์ดํฐ๊ฐ ์ ์ ํ
์ด๋ธ
๋ช ๋ฐฑ ๊ฑด ์ ๋์ ์์ ํ
์ด๋ธ์ Full Table Scan์ด ์คํ๋ ค ๋น ๋ฅผ ์ ์์ด. ์ธ๋ฑ์ค ๊ด๋ฆฌ ๋น์ฉ๋ง ๋์ด๋์ง.
2. INSERT, UPDATE, DELETE๊ฐ ๋น๋ฒํ ์ปฌ๋ผ
์ธ๋ฑ์ค๋ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ํจ๊ป ์
๋ฐ์ดํธ๋์ด์ผ ํด. ์ฐ๊ธฐ ์์
์ด ๋ง์ผ๋ฉด ์ธ๋ฑ์ค๊ฐ ์คํ๋ ค ์ฑ๋ฅ์ ๋จ์ด๋จ๋ฆด ์ ์์ด. ๐
3. ์นด๋๋๋ฆฌํฐ๊ฐ ๋งค์ฐ ๋ฎ์ ์ปฌ๋ผ
์ฑ๋ณ, ์ฐธ/๊ฑฐ์ง ๊ฐ์ ์ปฌ๋ผ์ ์ธ๋ฑ์ค ํจ๊ณผ๊ฐ ๊ฑฐ์ ์์ด. ์ ์ฒด ๋ฐ์ดํฐ์ ์ ๋ฐ ์ ๋๋ฅผ ์ฝ์ด์ผ ํ๋ค๋ฉด ์ธ๋ฑ์ค๋ฅผ ํ๋ ๊ฒ ์๋ฏธ๊ฐ ์๊ฑฐ๋ .
4. ์ปฌ๋ผ ๊ฐ์ด ์์ฃผ ๋ณ๊ฒฝ๋๋ ๊ฒฝ์ฐ
์ธ๋ฑ์ค ์ฌ๊ตฌ์ฑ ๋น์ฉ์ด ๊ณ์ ๋ฐ์ํด์ ์ ์ฒด์ ์ธ ์ฑ๋ฅ์ด ๋๋น ์ง ์ ์์ด.
๋ณตํฉ ์ธ๋ฑ์ค ์ค๊ณ ์์น
๋ณตํฉ ์ธ๋ฑ์ค๋ฅผ ๋ง๋ค ๋๋ ์ปฌ๋ผ ์์๊ฐ ์ ๋ง ์ค์ํด. ๋ค์ ์์น์ ๊ธฐ์ตํ์! ๐
๐ ๋ณตํฉ ์ธ๋ฑ์ค ์ปฌ๋ผ ์์ ๊ฒฐ์ ๋ฐฉ๋ฒ
1. ์นด๋๋๋ฆฌํฐ๊ฐ ๋์ ์ปฌ๋ผ์ ์์
๊ณ ์ ํ ๊ฐ์ด ๋ง์ ์ปฌ๋ผ์ ๋จผ์ ๋ฐฐ์นํ๋ฉด ์ด๊ธฐ ํํฐ๋ง์ด ํจ๊ณผ์ ์ด์ผ.
2. WHERE ์ ์์ = ์กฐ๊ฑด์ผ๋ก ์ฌ์ฉ๋๋ ์ปฌ๋ผ์ ์์
๋ฑํธ ์กฐ๊ฑด์ด ๋ฒ์ ์กฐ๊ฑด๋ณด๋ค ์ ํ๋๊ฐ ๋์์ ๋จผ์ ์ค๋ ๊ฒ ์ข์.
3. ์์ฃผ ์ฌ์ฉ๋๋ ์กฐํฉ์ ์ฐ์
์ฟผ๋ฆฌ ํจํด์ ๋ถ์ํด์ ๊ฐ์ฅ ๋น๋ฒํ ์กฐํฉ์ ๊ธฐ์ค์ผ๋ก ์์๋ฅผ ์ ํด์ผ ํด.
-- ๋์ ์: ์นด๋๋๋ฆฌํฐ๊ฐ ๋ฎ์ ์ปฌ๋ผ์ด ์์
CREATE INDEX idx_bad ON orders (status, user_id, order_date);
-- status๋ '์ฃผ๋ฌธ์๋ฃ', '๋ฐฐ์ก์ค', '์ทจ์' ๋ฑ ๋ช ๊ฐ์ง ๊ฐ๋ง ์์
-- ์ข์ ์: ์นด๋๋๋ฆฌํฐ๊ฐ ๋์ ์ปฌ๋ผ์ด ์์
CREATE INDEX idx_good ON orders (user_id, order_date, status);
-- user_id๋ ๊ณ ์ ๊ฐ์ด ๋ง๊ณ , ์์ฃผ ๊ฒ์ ์กฐ๊ฑด์ผ๋ก ์ฌ์ฉ๋จ
-- ์ค์ ์ฟผ๋ฆฌ
SELECT * FROM orders
WHERE user_id = 12345
AND order_date >= '2024-01-01'
AND status = '๋ฐฐ์ก์ค';
-- ์ด ์ฟผ๋ฆฌ๋ idx_good ์ธ๋ฑ์ค๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ ์ ์์ด! โจ
๐ง ์ฟผ๋ฆฌ ์ต์ ํ ๊ธฐ๋ฒ
์ธ๋ฑ์ค๋ฅผ ์ ๋ง๋ค์๋ค๊ณ ๋์ด ์๋์ผ. ์ฟผ๋ฆฌ๋ฅผ ์ด๋ป๊ฒ ์์ฑํ๋๋์ ๋ฐ๋ผ ์ธ๋ฑ์ค๋ฅผ ์ ๋๋ก ํ์ฉํ ์๋, ๋ชปํ ์๋ ์์ด. ์ค์ ์ต์ ํ ๊ธฐ๋ฒ์ ์์๋ณด์! ๐ช
EXPLAIN์ผ๋ก ์คํ ๊ณํ ๋ถ์ํ๊ธฐ
์ฟผ๋ฆฌ ์ต์ ํ์ ์ฒซ๊ฑธ์์ EXPLAIN์ด์ผ. ์ด ๋ช ๋ น์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ฟผ๋ฆฌ๋ฅผ ์ด๋ป๊ฒ ์คํํ ๊ณํ์ธ์ง ๋ณด์ฌ์ค. ๋ง์น ์ฟผ๋ฆฌ์ X-ray๋ฅผ ์ฐ๋ ๊ฒ๊ณผ ๊ฐ์ง! ๐ฌ
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
-- ๊ฒฐ๊ณผ ์์:
-- id | select_type | table | type | possible_keys | key | rows | Extra
-- 1 | SIMPLE | users | ref | idx_email | idx_email | 1 | Using index
๐ก EXPLAIN ๊ฒฐ๊ณผ ํด์ํ๊ธฐ
type ์ปฌ๋ผ - ์ ๊ทผ ๋ฐฉ์์ ๋ํ๋ด. ์ฑ๋ฅ ์์๋:
system > const > eq_ref > ref > range > index > ALL
ALL์ Full Table Scan์ด๋๊น ํผํด์ผ ํด!
key ์ปฌ๋ผ - ์ค์ ๋ก ์ฌ์ฉ๋ ์ธ๋ฑ์ค๋ฅผ ๋ณด์ฌ์ค. NULL์ด๋ฉด ์ธ๋ฑ์ค๋ฅผ ์ ์ด ๊ฑฐ์ผ.
rows ์ปฌ๋ผ - ๊ฒ์ฌํ ์์ ํ ์. ์ด ์ซ์๊ฐ ์์์๋ก ์ข์!
Extra ์ปฌ๋ผ - ์ถ๊ฐ ์ ๋ณด๋ฅผ ์ ๊ณตํด.
โข Using index: ์ปค๋ฒ๋ง ์ธ๋ฑ์ค (์ต๊ณ !) ๐
โข Using where: WHERE ์ ๋ก ํํฐ๋ง
โข Using filesort: ์ ๋ ฌ ์์
ํ์ (๋๋ฆด ์ ์์)
โข Using temporary: ์์ ํ
์ด๋ธ ์ฌ์ฉ (ํผํ๋ ๊ฒ ์ข์)
์ธ๋ฑ์ค๋ฅผ ํ์ง ๋ชปํ๋ ์ฟผ๋ฆฌ ํจํด
์ธ๋ฑ์ค๊ฐ ์์ด๋ ์ฟผ๋ฆฌ๋ฅผ ์๋ชป ์์ฑํ๋ฉด ์ธ๋ฑ์ค๋ฅผ ํ์ฉํ์ง ๋ชปํด. ์ด๋ฐ ์ค์๋ค์ ํผํ์! โ ๏ธ
๐ซ ์ธ๋ฑ์ค ํฌ๋ฌ ํจํด๋ค
1. ์ธ๋ฑ์ค ์ปฌ๋ผ์ ํจ์๋ ์ฐ์ฐ ์ฌ์ฉ
-- โ ๋์ ์: ์ธ๋ฑ์ค๋ฅผ ๋ชป ํ
SELECT * FROM users WHERE YEAR(created_at) = 2024;
SELECT * FROM products WHERE price * 1.1 > 10000;
-- โ
์ข์ ์: ์ธ๋ฑ์ค๋ฅผ ํ
SELECT * FROM users WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';
SELECT * FROM products WHERE price > 10000 / 1.1;
2. LIKE ํจํด์ ์์ ์์ผ๋์นด๋ ์ฌ์ฉ
-- โ ๋์ ์: ์ธ๋ฑ์ค๋ฅผ ๋ชป ํ
SELECT * FROM users WHERE name LIKE '%ํ๊ธธ๋%';
SELECT * FROM users WHERE name LIKE '%๊ธธ๋';
-- โ
์ข์ ์: ์ธ๋ฑ์ค๋ฅผ ํ
SELECT * FROM users WHERE name LIKE 'ํ๊ธธ๋%';
-- ์๋ถ๋ถ์ด ๊ณ ์ ๋์ด ์์ผ๋ฉด ์ธ๋ฑ์ค ํ์ฉ ๊ฐ๋ฅ!
3. OR ์กฐ๊ฑด ์ฌ์ฉ (๊ฒฝ์ฐ์ ๋ฐ๋ผ)
-- โ ๋์ ์: ์ธ๋ฑ์ค๋ฅผ ์ ๋๋ก ๋ชป ํ
SELECT * FROM users WHERE name = 'ํ๊ธธ๋' OR age = 30;
-- โ
์ข์ ์: UNION์ผ๋ก ๋ถ๋ฆฌ
SELECT * FROM users WHERE name = 'ํ๊ธธ๋'
UNION
SELECT * FROM users WHERE age = 30;
-- ๋๋ IN ์ฌ์ฉ (๊ฐ์ ์ปฌ๋ผ์ผ ๋)
SELECT * FROM users WHERE user_id IN (1, 2, 3, 4, 5);
4. ๋ถ์ ์กฐ๊ฑด ์ฌ์ฉ
-- โ ๋์ ์: ์ธ๋ฑ์ค๋ฅผ ๋ชป ํ
SELECT * FROM users WHERE status != 'active';
SELECT * FROM users WHERE status NOT IN ('active', 'pending');
-- โ
์ข์ ์: ๊ธ์ ์กฐ๊ฑด์ผ๋ก ๋ณ๊ฒฝ
SELECT * FROM users WHERE status IN ('inactive', 'deleted', 'banned');
5. ๋ฐ์ดํฐ ํ์ ๋ถ์ผ์น
-- user_id๊ฐ INT ํ์
์ธ ๊ฒฝ์ฐ
-- โ ๋์ ์: ๋ฌธ์์ด๋ก ๋น๊ต (์๋ฌต์ ํ๋ณํ ๋ฐ์)
SELECT * FROM users WHERE user_id = '12345';
-- โ
์ข์ ์: ์ฌ๋ฐ๋ฅธ ํ์
์ผ๋ก ๋น๊ต
SELECT * FROM users WHERE user_id = 12345;
SELECT ์ ์ต์ ํ
๋ง์ ๊ฐ๋ฐ์๋ค์ด ์ต๊ด์ ์ผ๋ก SELECT *๋ฅผ ์ฌ์ฉํ๋๋ฐ, ์ด๊ฑด ์ฑ๋ฅ์ ์ข์ง ์์. ํ์ํ ์ปฌ๋ผ๋ง ๋ช ์ํ๋ ๊ฒ ํจ์ฌ ์ข์! ๐ฏ
โ ๋นํจ์จ์
SELECT *
FROM users
WHERE user_id = 100;
โข ๋ชจ๋ ์ปฌ๋ผ ์ฝ์
โข ๋คํธ์ํฌ ๋ถํ ์ฆ๊ฐ
โข ์ปค๋ฒ๋ง ์ธ๋ฑ์ค ํ์ฉ ๋ถ๊ฐ
โ ํจ์จ์
SELECT user_id, name, email
FROM users
WHERE user_id = 100;
โข ํ์ํ ์ปฌ๋ผ๋ง ์ฝ์
โข ๋คํธ์ํฌ ํจ์จ์
โข ์ปค๋ฒ๋ง ์ธ๋ฑ์ค ๊ฐ๋ฅ
JOIN ์ต์ ํ
JOIN์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๊ฐ์ฅ ๋น์ฉ์ด ํฐ ์ฐ์ฐ ์ค ํ๋์ผ. ์ ๋๋ก ์ต์ ํํ์ง ์์ผ๋ฉด ์ฑ๋ฅ์ด ๊ธ๊ฒฉํ ๋๋น ์ง์ง. ๐ฐ
๐ JOIN ์ต์ ํ ์ฒดํฌ๋ฆฌ์คํธ
1. JOIN ํค์ ์ธ๋ฑ์ค ์์ฑ
์์ชฝ ํ
์ด๋ธ์ JOIN ์กฐ๊ฑด ์ปฌ๋ผ์ ๋ชจ๋ ์ธ๋ฑ์ค๊ฐ ์์ด์ผ ํด.
2. ์์ ํ
์ด๋ธ์ ๋จผ์ (Driving Table)
๊ฐ๋ฅํ๋ฉด ์์ ํ
์ด๋ธ์ ๊ธฐ์ค์ผ๋ก ํฐ ํ
์ด๋ธ์ ์กฐ์ธํ๋ ๊ฒ ํจ์จ์ ์ด์ผ.
3. ํ์ํ ๋ฐ์ดํฐ๋ง JOIN
WHERE ์ ๋ก ๋จผ์ ํํฐ๋งํ ํ JOINํ๋ฉด ์ฒ๋ฆฌํ ๋ฐ์ดํฐ๊ฐ ์ค์ด๋ค์ด.
4. JOIN ํ์
์ ํ
INNER JOIN์ด OUTER JOIN๋ณด๋ค ๋น ๋ฅด๋๊น, ๊ผญ ํ์ํ ๊ฒฝ์ฐ๊ฐ ์๋๋ฉด INNER JOIN์ ์ฌ์ฉํ์.
-- โ ๋นํจ์จ์ ์ธ JOIN
SELECT u.*, o.*, p.*
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
LEFT JOIN products p ON o.product_id = p.product_id;
-- โ
์ต์ ํ๋ JOIN
SELECT u.user_id, u.name, o.order_id, o.order_date, p.product_name
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
INNER JOIN products p ON o.product_id = p.product_id
WHERE o.order_date >= '2024-01-01'
AND o.status = 'completed';
-- ํ์ํ ์ปฌ๋ผ๋ง ์ ํ, WHERE๋ก ๋จผ์ ํํฐ๋ง, INNER JOIN ์ฌ์ฉ
์๋ธ์ฟผ๋ฆฌ vs JOIN
์๋ธ์ฟผ๋ฆฌ๋ ๊ฐ๋ ์ฑ์ ์ข์ง๋ง ์ฑ๋ฅ์ JOIN๋ณด๋ค ๋จ์ด์ง ์ ์์ด. ํนํ ์๊ด ์๋ธ์ฟผ๋ฆฌ(Correlated Subquery)๋ ์กฐ์ฌํด์ผ ํด! ๐จ
-- โ ๋๋ฆฐ ์๊ด ์๋ธ์ฟผ๋ฆฌ
SELECT u.user_id, u.name,
(SELECT COUNT(*) FROM orders o WHERE o.user_id = u.user_id) as order_count
FROM users u;
-- ๊ฐ ์ฌ์ฉ์๋ง๋ค ์๋ธ์ฟผ๋ฆฌ๊ฐ ์คํ๋จ (N+1 ๋ฌธ์ )
-- โ
๋น ๋ฅธ JOIN ๋ฐฉ์
SELECT u.user_id, u.name, COUNT(o.order_id) as order_count
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
GROUP BY u.user_id, u.name;
-- ํ ๋ฒ์ JOIN์ผ๋ก ์ฒ๋ฆฌ
ํ์ง๋ง ์๋ธ์ฟผ๋ฆฌ๊ฐ ๋ ๋์ ๊ฒฝ์ฐ๋ ์์ด. EXISTS๋ IN์ ์ฌ์ฉํ ๋๋ ์ตํฐ๋ง์ด์ ๊ฐ ์ ์ฒ๋ฆฌํด์ฃผ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์. ํญ์ EXPLAIN์ผ๋ก ํ์ธํ๋ ๊ฒ ์ค์ํด! ๐
๐ ์ธ๋ฑ์ค ๋ชจ๋ํฐ๋ง๊ณผ ์ ์ง๋ณด์
์ธ๋ฑ์ค๋ฅผ ๋ง๋ค๊ณ ๋์ด ์๋์ผ. ์๊ฐ์ด ์ง๋๋ฉด์ ๋ฐ์ดํฐ๊ฐ ๋ณํ๊ณ , ์ฟผ๋ฆฌ ํจํด๋ ๋ฐ๋๊ธฐ ๋๋ฌธ์ ์ง์์ ์ธ ๋ชจ๋ํฐ๋ง๊ณผ ๊ด๋ฆฌ๊ฐ ํ์ํด. ๐ง
์ฌ์ฉ๋์ง ์๋ ์ธ๋ฑ์ค ์ฐพ๊ธฐ
์ธ๋ชจ์๋ ์ธ๋ฑ์ค๋ ์ ์ฅ ๊ณต๊ฐ๋ง ์ฐจ์งํ๊ณ ์ฐ๊ธฐ ์ฑ๋ฅ์ ๋จ์ด๋จ๋ ค. ์ ๊ธฐ์ ์ผ๋ก ์ ๊ฒํด์ ์ ๊ฑฐํด์ผ ํด!
-- MySQL์์ ์ฌ์ฉ๋์ง ์๋ ์ธ๋ฑ์ค ์ฐพ๊ธฐ
SELECT
s.table_schema,
s.table_name,
s.index_name,
s.rows_read
FROM performance_schema.table_io_waits_summary_by_index_usage s
WHERE s.index_name IS NOT NULL
AND s.rows_read = 0
AND s.table_schema NOT IN ('mysql', 'performance_schema', 'information_schema')
ORDER BY s.table_schema, s.table_name;
์ค๋ณต ์ธ๋ฑ์ค ์ ๊ฑฐ
์ค๋ณต ์ธ๋ฑ์ค๋ ์์ธ๋ก ํํด. ์๋ฅผ ๋ค์ด (A) ์ธ๋ฑ์ค์ (A, B) ์ธ๋ฑ์ค๊ฐ ๋์์ ์์ผ๋ฉด, (A) ์ธ๋ฑ์ค๋ ์ฌ์ค์ ๋ถํ์ํด. (A, B) ์ธ๋ฑ์ค๊ฐ A๋ง์ผ๋ก๋ ๊ฒ์ํ ์ ์๊ฑฐ๋ ! ๐ฏ
โ ๏ธ ์ค๋ณต ์ธ๋ฑ์ค ์์
๋ถํ์ํ ์ค๋ณต:
โข INDEX (user_id)
โข INDEX (user_id, created_at) โ ์ด๊ฒ๋ง ์์ผ๋ฉด ๋จ
ํ์ํ ๋ณ๋ ์ธ๋ฑ์ค:
โข INDEX (user_id, created_at)
โข INDEX (created_at, user_id) โ ์์๊ฐ ๋ค๋ฅด๋ฉด ๋ค๋ฅธ ์ฉ๋๋ก ์ฌ์ฉ ๊ฐ๋ฅ
์ธ๋ฑ์ค ํต๊ณ ์ ๋ฐ์ดํธ
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ์ธ๋ฑ์ค ํต๊ณ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์คํ ๊ณํ์ ์ธ์. ํต๊ณ๊ฐ ์ค๋๋๋ฉด ์๋ชป๋ ๊ณํ์ ์ธ์ธ ์ ์์ด์ ์ ๊ธฐ์ ์ผ๋ก ์ ๋ฐ์ดํธํด์ผ ํด! ๐
-- MySQL
ANALYZE TABLE users;
-- PostgreSQL
ANALYZE users;
-- SQL Server
UPDATE STATISTICS users;
์ธ๋ฑ์ค ๋จํธํ ๊ด๋ฆฌ
์๊ฐ์ด ์ง๋๋ฉด์ ๋ฐ์ดํฐ์ ์ฝ์ , ์์ , ์ญ์ ๊ฐ ๋ฐ๋ณต๋๋ฉด ์ธ๋ฑ์ค๊ฐ ๋จํธํ(Fragmentation)๋ผ. ์ด๋ฌ๋ฉด ์ฑ๋ฅ์ด ๋จ์ด์ง๋๊น ์ฌ๊ตฌ์ฑ์ด ํ์ํด!
๐ก ์ธ๋ฑ์ค ์ฌ๊ตฌ์ฑ vs ์ฌ๊ตฌ์ถ
์ฌ๊ตฌ์ฑ(Reorganize):
โข ์จ๋ผ์ธ์ผ๋ก ์คํ ๊ฐ๋ฅ
โข ๋จํธํ๊ฐ ์ฌํ์ง ์์ ๋ (10~30%)
โข ๋น ๋ฅด๊ณ ๋ถ๋ด์ด ์ ์
์ฌ๊ตฌ์ถ(Rebuild):
โข ์คํ๋ผ์ธ ์์
(ํ
์ด๋ธ ์ ๊ธ)
โข ๋จํธํ๊ฐ ์ฌํ ๋ (30% ์ด์)
โข ์์ ํ ์๋ก ๋ง๋ค์ด์ ์ต์ ์ํ๋ก ๋ณต์
-- MySQL (InnoDB)
OPTIMIZE TABLE users;
-- SQL Server
-- ์ฌ๊ตฌ์ฑ
ALTER INDEX idx_user_email ON users REORGANIZE;
-- ์ฌ๊ตฌ์ถ
ALTER INDEX idx_user_email ON users REBUILD;
๐ช ์ค์ ์ฌ๋ก ์ฐ๊ตฌ
์ด๋ก ๋ง์ผ๋ก๋ ๋ถ์กฑํ์ง! ์ค์ ์ํฉ์์ ์ด๋ป๊ฒ ์ ์ฉํ๋์ง ๊ตฌ์ฒด์ ์ธ ์ฌ๋ก๋ฅผ ์ดํด๋ณด์. ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์ ์๋ก ๋ค์ด๋ณผ๊ฒ! ๐
์ฌ๋ก 1: ์ฌ์ฉ์ ๊ฒ์ ๊ธฐ๋ฅ ์ต์ ํ
๐ ์ํฉ
์ฌ๋ฅ๋ท์์ ์ฌ์ฉ์๊ฐ ํน์ ์ฌ๋ฅ์ ๊ฐ์ง ์ ๋ฌธ๊ฐ๋ฅผ ๊ฒ์ํ๋ ๊ธฐ๋ฅ์ด ์์ด. ๊ฒ์ ์กฐ๊ฑด์ ๋ค์๊ณผ ๊ฐ์:
โข ์นดํ
๊ณ ๋ฆฌ (์: ๋์์ธ, ํ๋ก๊ทธ๋๋ฐ, ๋ง์ผํ
)
โข ์ง์ญ
โข ํ์ 4.0 ์ด์
โข ์ต๊ทผ ํ๋์ผ ๊ธฐ์ค ์ ๋ ฌ
-- ์ด๊ธฐ ์ฟผ๋ฆฌ (๋๋ฆผ ๐ข)
SELECT * FROM experts
WHERE category = 'ํ๋ก๊ทธ๋๋ฐ'
AND region = '์์ธ'
AND rating >= 4.0
ORDER BY last_active_date DESC
LIMIT 20;
-- ์คํ ์๊ฐ: 8.5์ด
-- ๋ฌธ์ : ์ธ๋ฑ์ค ์์, Full Table Scan
โ ํด๊ฒฐ ๋ฐฉ๋ฒ
1๋จ๊ณ: ๋ณตํฉ ์ธ๋ฑ์ค ์์ฑ
CREATE INDEX idx_expert_search
ON experts (category, region, rating, last_active_date);
-- ์ปฌ๋ผ ์์ ์ด์ :
-- 1. category: ์นด๋๋๋ฆฌํฐ ์ค๊ฐ, ํ์ ์กฐ๊ฑด
-- 2. region: ์นด๋๋๋ฆฌํฐ ์ค๊ฐ, ํ์ ์กฐ๊ฑด
-- 3. rating: ๋ฒ์ ์กฐ๊ฑด
-- 4. last_active_date: ORDER BY์ ์ฌ์ฉ
2๋จ๊ณ: ์ฟผ๋ฆฌ ๊ฐ์
-- ์ต์ ํ๋ ์ฟผ๋ฆฌ (๋น ๋ฆ ๐)
SELECT expert_id, name, category, region, rating, last_active_date
FROM experts
WHERE category = 'ํ๋ก๊ทธ๋๋ฐ'
AND region = '์์ธ'
AND rating >= 4.0
ORDER BY last_active_date DESC
LIMIT 20;
-- ์คํ ์๊ฐ: 0.02์ด
-- ๊ฐ์ : 425๋ฐฐ ๋น ๋ฆ!
-- Using index (์ปค๋ฒ๋ง ์ธ๋ฑ์ค ํ์ฉ)
์ฌ๋ก 2: ๊ฑฐ๋ ๋ด์ญ ์กฐํ ์ต์ ํ
๐ ์ํฉ
์ฌ์ฉ์๊ฐ ์์ ์ ๊ฑฐ๋ ๋ด์ญ์ ์กฐํํ๋ ๊ธฐ๋ฅ. ์ต๊ทผ 3๊ฐ์ ๊ฑฐ๋๋ฅผ ๋ ์ง ์ญ์์ผ๋ก ๋ณด์ฌ์ค์ผ ํด. ๊ฑฐ๋ ํ ์ด๋ธ์๋ 1,000๋ง ๊ฑด์ ๋ฐ์ดํฐ๊ฐ ์์ด.
-- ์ด๊ธฐ ์ฟผ๋ฆฌ (๋งค์ฐ ๋๋ฆผ ๐)
SELECT t.*, u.name as user_name, e.name as expert_name
FROM transactions t
LEFT JOIN users u ON t.user_id = u.user_id
LEFT JOIN experts e ON t.expert_id = e.expert_id
WHERE t.user_id = 12345
AND t.created_at >= DATE_SUB(NOW(), INTERVAL 3 MONTH)
ORDER BY t.created_at DESC;
-- ์คํ ์๊ฐ: 15์ด
-- ๋ฌธ์ : ๋นํจ์จ์ ์ธ JOIN, ์ธ๋ฑ์ค ๋ฏธํ์ฉ
โ ํด๊ฒฐ ๋ฐฉ๋ฒ
1๋จ๊ณ: ์ ์ ํ ์ธ๋ฑ์ค ์์ฑ
-- transactions ํ
์ด๋ธ
CREATE INDEX idx_user_date ON transactions (user_id, created_at DESC);
-- users, experts ํ
์ด๋ธ (์ด๋ฏธ PK ์ธ๋ฑ์ค ์์)
-- user_id, expert_id๋ ์ด๋ฏธ Primary Key๋ก ์ธ๋ฑ์ค๋จ
2๋จ๊ณ: ์ฟผ๋ฆฌ ์ต์ ํ
-- ์ต์ ํ๋ ์ฟผ๋ฆฌ (๋น ๋ฆ ๐)
SELECT
t.transaction_id,
t.amount,
t.status,
t.created_at,
u.name as user_name,
e.name as expert_name
FROM transactions t
INNER JOIN users u ON t.user_id = u.user_id
INNER JOIN experts e ON t.expert_id = e.expert_id
WHERE t.user_id = 12345
AND t.created_at >= DATE_SUB(NOW(), INTERVAL 3 MONTH)
ORDER BY t.created_at DESC
LIMIT 50;
-- ์คํ ์๊ฐ: 0.05์ด
-- ๊ฐ์ : 300๋ฐฐ ๋น ๋ฆ!
-- ๋ณ๊ฒฝ์ฌํญ:
-- 1. ํ์ํ ์ปฌ๋ผ๋ง SELECT
-- 2. LEFT JOIN โ INNER JOIN (NULL ๋ฐ์ดํฐ ์์)
-- 3. LIMIT ์ถ๊ฐ (ํ์ด์ง)
-- 4. ์ธ๋ฑ์ค ํ์ฉ
์ฌ๋ก 3: ์ธ๊ธฐ ์ฌ๋ฅ ๋ญํน ์กฐํ
๐ ์ํฉ
๋ฉ์ธ ํ์ด์ง์ "์ด๋ฒ ์ฃผ ์ธ๊ธฐ ์ฌ๋ฅ TOP 10"์ ๋ณด์ฌ์ฃผ๋ ๊ธฐ๋ฅ. ์กฐํ์, ์ฐํ๊ธฐ ์, ๊ฑฐ๋ ๊ฑด์๋ฅผ ์ข ํฉํด์ ๊ณ์ฐํด์ผ ํด.
-- ์ด๊ธฐ ์ฟผ๋ฆฌ (์์ฒญ ๋๋ฆผ ๐ฑ)
SELECT
s.service_id,
s.title,
(SELECT COUNT(*) FROM service_views WHERE service_id = s.service_id
AND viewed_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)) as view_count,
(SELECT COUNT(*) FROM service_likes WHERE service_id = s.service_id) as like_count,
(SELECT COUNT(*) FROM transactions WHERE service_id = s.service_id
AND created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)) as transaction_count
FROM services s
WHERE s.status = 'active'
ORDER BY (view_count + like_count * 2 + transaction_count * 5) DESC
LIMIT 10;
-- ์คํ ์๊ฐ: 45์ด
-- ๋ฌธ์ : N+1 ๋ฌธ์ , ์๊ด ์๋ธ์ฟผ๋ฆฌ ๋จ๋ฐ
โ ํด๊ฒฐ ๋ฐฉ๋ฒ
1๋จ๊ณ: ์ง๊ณ ํ ์ด๋ธ ์์ฑ (Materialized View ๊ฐ๋ )
-- ์ฃผ๊ฐ ํต๊ณ ํ
์ด๋ธ ์์ฑ
CREATE TABLE service_weekly_stats (
service_id INT PRIMARY KEY,
view_count INT DEFAULT 0,
like_count INT DEFAULT 0,
transaction_count INT DEFAULT 0,
popularity_score INT DEFAULT 0,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_popularity (popularity_score DESC, updated_at)
);
-- ๋ฐฐ์น ์์
์ผ๋ก 1์๊ฐ๋ง๋ค ์
๋ฐ์ดํธ
INSERT INTO service_weekly_stats (service_id, view_count, like_count, transaction_count, popularity_score)
SELECT
s.service_id,
COALESCE(v.view_count, 0) as view_count,
COALESCE(l.like_count, 0) as like_count,
COALESCE(t.transaction_count, 0) as transaction_count,
(COALESCE(v.view_count, 0) + COALESCE(l.like_count, 0) * 2 + COALESCE(t.transaction_count, 0) * 5) as popularity_score
FROM services s
LEFT JOIN (
SELECT service_id, COUNT(*) as view_count
FROM service_views
WHERE viewed_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY service_id
) v ON s.service_id = v.service_id
LEFT JOIN (
SELECT service_id, COUNT(*) as like_count
FROM service_likes
GROUP BY service_id
) l ON s.service_id = l.service_id
LEFT JOIN (
SELECT service_id, COUNT(*) as transaction_count
FROM transactions
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY service_id
) t ON s.service_id = t.service_id
WHERE s.status = 'active'
ON DUPLICATE KEY UPDATE
view_count = VALUES(view_count),
like_count = VALUES(like_count),
transaction_count = VALUES(transaction_count),
popularity_score = VALUES(popularity_score),
updated_at = CURRENT_TIMESTAMP;
2๋จ๊ณ: ๊ฐ๋จํ ์กฐํ ์ฟผ๋ฆฌ
-- ์ต์ ํ๋ ์ฟผ๋ฆฌ (์ด๊ณ ์ โก)
SELECT
s.service_id,
s.title,
s.thumbnail,
st.view_count,
st.like_count,
st.transaction_count,
st.popularity_score
FROM services s
INNER JOIN service_weekly_stats st ON s.service_id = st.service_id
WHERE s.status = 'active'
ORDER BY st.popularity_score DESC
LIMIT 10;
-- ์คํ ์๊ฐ: 0.003์ด
-- ๊ฐ์ : 15,000๋ฐฐ ๋น ๋ฆ!
-- ํธ๋ ์ด๋์คํ: ์ค์๊ฐ์ฑ์ ์ฝ๊ฐ ๋จ์ด์ง์ง๋ง (1์๊ฐ ์ง์ฐ)
-- ์ฌ์ฉ์ ๊ฒฝํ์ ํจ์ฌ ์ข์์ง
๐ ๊ตํ
๋๋ก๋ ์ฟผ๋ฆฌ ์ต์ ํ๋ง์ผ๋ก๋ ํ๊ณ๊ฐ ์์ด. ์ด๋ด ๋๋ ๋ฐ์ดํฐ ๊ตฌ์กฐ ์์ฒด๋ฅผ ์ฌ์ค๊ณํ๋ ๊ฒ ๋ต์ด์ผ. ์ง๊ณ ํ ์ด๋ธ, ์บ์, ๋น์ ๊ทํ ๋ฑ์ ๊ธฐ๋ฒ์ ์ ์ ํ ํ์ฉํ๋ฉด ๊ทน์ ์ธ ์ฑ๋ฅ ๊ฐ์ ์ ์ด๋ฃฐ ์ ์์ด! ๐ก
๐ ๊ณ ๊ธ ์ต์ ํ ๊ธฐ๋ฒ
๊ธฐ๋ณธ์ ์ธ ์ธ๋ฑ์ค์ ์ฟผ๋ฆฌ ์ต์ ํ๋ฅผ ๋์ด์, ๋ ๋์ ์์ค์ ์ฑ๋ฅ์ ์ํ๋ค๋ฉด ์ด๋ฐ ๊ณ ๊ธ ๊ธฐ๋ฒ๋ค๋ ์์๋๋ฉด ์ข์! ๐
ํํฐ์ ๋ (Partitioning)
ํํฐ์ ๋์ ํฐ ํ ์ด๋ธ์ ์ฌ๋ฌ ๊ฐ์ ์์ ์กฐ๊ฐ์ผ๋ก ๋๋๋ ๊ธฐ๋ฒ์ด์ผ. ํนํ ์๊ณ์ด ๋ฐ์ดํฐ๋ ๋์ฉ๋ ๋ก๊ทธ ๋ฐ์ดํฐ์ ํจ๊ณผ์ ์ด์ง! ๐
๐ก ํํฐ์ ๋์ ์ฅ์
โข ์ฟผ๋ฆฌ ์ฑ๋ฅ ํฅ์: ํ์ํ ํํฐ์
๋ง ์ค์บ
โข ๊ด๋ฆฌ ์ฉ์ด์ฑ: ์ค๋๋ ๋ฐ์ดํฐ ํํฐ์
๋ง ์ญ์ ๊ฐ๋ฅ
โข ๋ณ๋ ฌ ์ฒ๋ฆฌ: ์ฌ๋ฌ ํํฐ์
์ ๋์์ ์ฒ๋ฆฌ
โข ๋ฐฑ์
/๋ณต๊ตฌ ํจ์จ: ํํฐ์
๋จ์๋ก ์์
๊ฐ๋ฅ
-- ๋ ์ง ๊ธฐ์ค ํํฐ์
๋ ์์
CREATE TABLE transactions (
transaction_id BIGINT AUTO_INCREMENT,
user_id INT NOT NULL,
amount DECIMAL(10,2),
created_at DATETIME NOT NULL,
PRIMARY KEY (transaction_id, created_at),
INDEX idx_user (user_id)
)
PARTITION BY RANGE (YEAR(created_at)) (
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026),
PARTITION p_future VALUES LESS THAN MAXVALUE
);
-- 2024๋
๋ฐ์ดํฐ๋ง ์กฐํ (p2024 ํํฐ์
๋ง ์ค์บ)
SELECT * FROM transactions
WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';
-- 2022๋
๋ฐ์ดํฐ ์ญ์ (ํํฐ์
ํต์งธ๋ก ์ญ์ , ๋งค์ฐ ๋น ๋ฆ!)
ALTER TABLE transactions DROP PARTITION p2022;
์ฟผ๋ฆฌ ์บ์ฑ๊ณผ ๊ฒฐ๊ณผ ์บ์ฑ
๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ๋ฐ๋ณต ์คํํ๋ค๋ฉด ๊ฒฐ๊ณผ๋ฅผ ์บ์ฑํ๋ ๊ฒ ํจ์จ์ ์ด์ผ. ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ ๋ฒจ์ด๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ ๋ฒจ์์ ์บ์ฑ์ ํ์ฉํ ์ ์์ด. ๐๏ธ
์บ์ฑ ์ ๋ต
1. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ ์บ์
MySQL์ Query Cache (8.0๋ถํฐ๋ ์ ๊ฑฐ๋จ) ๊ฐ์ ๊ธฐ๋ฅ. ์์ฆ์ ์ ํ๋ฆฌ์ผ์ด์
๋ ๋ฒจ ์บ์ฑ์ ๋ ์ ํธํด.
2. Redis/Memcached ํ์ฉ
์์ฃผ ์กฐํ๋๋ ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์บ์ฑ. ์ฝ๊ธฐ ์ฑ๋ฅ์ด ๊ทน์ ์ผ๋ก ํฅ์๋ผ!
3. CDN ์บ์ฑ
์ ์ ์ฝํ
์ธ ๋ API ์๋ต์ ์ฃ์ง ์๋ฒ์ ์บ์ฑ.
// Node.js + Redis ์บ์ฑ ์์
const redis = require('redis');
const client = redis.createClient();
async function getPopularServices() {
const cacheKey = 'popular_services:top10';
// 1. ์บ์ ํ์ธ
const cached = await client.get(cacheKey);
if (cached) {
console.log('์บ์ ํํธ! ๐ฏ');
return JSON.parse(cached);
}
// 2. ์บ์ ๋ฏธ์ค - DB ์กฐํ
console.log('์บ์ ๋ฏธ์ค, DB ์กฐํ ์ค... ๐');
const result = await db.query(`
SELECT service_id, title, popularity_score
FROM service_weekly_stats
ORDER BY popularity_score DESC
LIMIT 10
`);
// 3. ๊ฒฐ๊ณผ๋ฅผ ์บ์์ ์ ์ฅ (5๋ถ TTL)
await client.setex(cacheKey, 300, JSON.stringify(result));
return result;
}
// ์ฒซ ํธ์ถ: DB ์กฐํ (0.003์ด)
// ์ดํ ํธ์ถ: ์บ์ ๋ฐํ (0.0001์ด) - 30๋ฐฐ ๋น ๋ฆ!
์ฝ๊ธฐ ์ ์ฉ ๋ณต์ ๋ณธ (Read Replica)
์ฐ๊ธฐ๋ ๋ง์คํฐ DB์์, ์ฝ๊ธฐ๋ ๋ณต์ ๋ณธ์์ ์ฒ๋ฆฌํ๋ฉด ๋ถํ๋ฅผ ๋ถ์ฐ์ํฌ ์ ์์ด. ํนํ ์ฝ๊ธฐ๊ฐ ๋ง์ ์๋น์ค์ ํจ๊ณผ์ ์ด์ง! ๐
๋ง์คํฐ DB
โข INSERT, UPDATE, DELETE
โข ์ค์ํ SELECT (์ค์๊ฐ ํ์)
โข ํธ๋์ญ์ ์ฒ๋ฆฌ
๋ณต์ ๋ณธ DB
โข ๋๋ถ๋ถ์ SELECT
โข ํต๊ณ, ๋ฆฌํฌํธ ์กฐํ
โข ๊ฒ์ ๊ธฐ๋ฅ
๋น์ ๊ทํ (Denormalization)
์ ๊ทํ๋ ๋ฐ์ดํฐ ์ค๋ณต์ ์์ ๋ ๊ฑฐ์ง๋ง, ๋๋ก๋ ์๋์ ์ผ๋ก ์ค๋ณต์ ํ์ฉํด์ ์ฑ๋ฅ์ ๋์ด๋ ๊ฒ ๋์ ์ ์์ด. ์ด๊ฒ ๋น์ ๊ทํ์ผ! โ๏ธ
โ ๏ธ ๋น์ ๊ทํ ์ ์ฃผ์์ฌํญ
๋น์ ๊ทํ๋ ์ฝ๊ธฐ ์ฑ๋ฅ์ ์ํด ์ฐ๊ธฐ ๋ณต์ก๋๋ฅผ ํฌ์ํ๋ ๊ฑฐ์ผ. ์ ์คํ๊ฒ ๊ฒฐ์ ํด์ผ ํด!
๊ณ ๋ ค์ฌํญ:
โข ๋ฐ์ดํฐ ์ผ๊ด์ฑ ์ ์ง ๋ฐฉ๋ฒ
โข ์
๋ฐ์ดํธ ๋น๋ vs ์กฐํ ๋น๋
โข ์ถ๊ฐ ์ ์ฅ ๊ณต๊ฐ ๋น์ฉ
โข ๋๊ธฐํ ๋ก์ง์ ๋ณต์ก๋
-- ์ ๊ทํ๋ ๊ตฌ์กฐ (JOIN ํ์)
SELECT u.name, COUNT(o.order_id) as order_count
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
GROUP BY u.user_id, u.name;
-- ๋น์ ๊ทํ๋ ๊ตฌ์กฐ (JOIN ๋ถํ์)
-- users ํ
์ด๋ธ์ order_count ์ปฌ๋ผ ์ถ๊ฐ
SELECT name, order_count FROM users WHERE user_id = 123;
-- ์ฃผ๋ฌธ์ด ์๊ธธ ๋๋ง๋ค users.order_count๋ ์
๋ฐ์ดํธ
BEGIN;
INSERT INTO orders (user_id, product_id, amount) VALUES (123, 456, 50000);
UPDATE users SET order_count = order_count + 1 WHERE user_id = 123;
COMMIT;
๋ฐฐ์น ์ฒ๋ฆฌ์ ๋ฒํฌ ์ฐ์ฐ
๋๋์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ๋๋ ํ๋์ฉ ์ฒ๋ฆฌํ์ง ๋ง๊ณ ๋ฐฐ์น๋ก ๋ฌถ์ด์ ์ฒ๋ฆฌํ๋ฉด ํจ์ฌ ๋นจ๋ผ! ๐
-- โ ๋๋ฆฐ ๋ฐฉ๋ฒ: ํ๋์ฉ INSERT (N๋ฒ์ ์ฟผ๋ฆฌ)
INSERT INTO logs (user_id, action, created_at) VALUES (1, 'login', NOW());
INSERT INTO logs (user_id, action, created_at) VALUES (2, 'view', NOW());
INSERT INTO logs (user_id, action, created_at) VALUES (3, 'purchase', NOW());
-- ... 10,000๋ฒ ๋ฐ๋ณต
-- โ
๋น ๋ฅธ ๋ฐฉ๋ฒ: ๋ฒํฌ INSERT (1๋ฒ์ ์ฟผ๋ฆฌ)
INSERT INTO logs (user_id, action, created_at) VALUES
(1, 'login', NOW()),
(2, 'view', NOW()),
(3, 'purchase', NOW()),
-- ... 10,000๊ฐ๋ฅผ ํ ๋ฒ์
(10000, 'logout', NOW());
-- ์ฑ๋ฅ ์ฐจ์ด: 100๋ฐฐ ์ด์!
๐ ๋ฒํฌ ์ฐ์ฐ ํ
โข ํ ๋ฒ์ ๋๋ฌด ๋ง์ด ์ฒ๋ฆฌํ๋ฉด ๋ฉ๋ชจ๋ฆฌ ๋ฌธ์ ๋ฐ์ ๊ฐ๋ฅ
โข ์ ์ ํ ๋ฐฐ์น ํฌ๊ธฐ: 1,000~10,000๊ฑด
โข ํธ๋์ญ์
ํฌ๊ธฐ๋ ๊ณ ๋ คํด์ผ ํจ
โข ์คํจ ์ ์ฌ์ฒ๋ฆฌ ๋ก์ง ํ์
๐ ๏ธ ์ค๋ฌด ์ฒดํฌ๋ฆฌ์คํธ
์ง๊ธ๊น์ง ๋ฐฐ์ด ๋ด์ฉ์ ์ค๋ฌด์ ์ ์ฉํ ๋ ์ฐธ๊ณ ํ ์ ์๋ ์ฒดํฌ๋ฆฌ์คํธ๋ฅผ ๋ง๋ค์ด๋ดค์ด. ํ๋ก์ ํธ์์ ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ์๊ฒผ์ ๋ ํ๋์ฉ ์ ๊ฒํด๋ณด์! โ
๐ฏ ์ธ๋ฑ์ค ์ค๊ณ ์ฒดํฌ๋ฆฌ์คํธ
โก WHERE ์ ์ ์์ฃผ ์ฌ์ฉ๋๋ ์ปฌ๋ผ์ ์ธ๋ฑ์ค ์์ฑํ๋๊ฐ?
โก JOIN ์กฐ๊ฑด ์ปฌ๋ผ์ ์ธ๋ฑ์ค๊ฐ ์๋๊ฐ?
โก ๋ณตํฉ ์ธ๋ฑ์ค์ ์ปฌ๋ผ ์์๊ฐ ์ ์ ํ๊ฐ? (์นด๋๋๋ฆฌํฐ, ์ฌ์ฉ ๋น๋ ๊ณ ๋ ค)
โก ์ปค๋ฒ๋ง ์ธ๋ฑ์ค๋ฅผ ํ์ฉํ ์ ์๋๊ฐ?
โก ์ฌ์ฉ๋์ง ์๋ ์ธ๋ฑ์ค๋ ์ ๊ฑฐํ๋๊ฐ?
โก ์ค๋ณต ์ธ๋ฑ์ค๋ ์๋๊ฐ?
โก ์ธ๋ฑ์ค ํต๊ณ๊ฐ ์ต์ ์ธ๊ฐ?
๐ ์ฟผ๋ฆฌ ์ต์ ํ ์ฒดํฌ๋ฆฌ์คํธ
โก EXPLAIN์ผ๋ก ์คํ ๊ณํ์ ํ์ธํ๋๊ฐ?
โก Full Table Scan์ด ๋ฐ์ํ๋๊ฐ? (type = ALL)
โก SELECT *๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ํ์ํ ์ปฌ๋ผ๋ง ์ ํํ๋๊ฐ?
โก ์ธ๋ฑ์ค ์ปฌ๋ผ์ ํจ์๋ ์ฐ์ฐ์ ์ฌ์ฉํ์ง ์์๋๊ฐ?
โก LIKE ํจํด์ ์์ ์์ผ๋์นด๋๋ฅผ ์ฌ์ฉํ์ง ์์๋๊ฐ?
โก ์๊ด ์๋ธ์ฟผ๋ฆฌ๋ฅผ JOIN์ผ๋ก ๋ณ๊ฒฝํ ์ ์๋๊ฐ?
โก ์ ์ ํ LIMIT๋ฅผ ์ฌ์ฉํ๋๊ฐ?
โก ๋ฐ์ดํฐ ํ์
์ด ์ผ์นํ๋๊ฐ?
โก ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง ์ฒดํฌ๋ฆฌ์คํธ
โก ์ฌ๋ก์ฐ ์ฟผ๋ฆฌ ๋ก๊ทธ๋ฅผ ์ ๊ธฐ์ ์ผ๋ก ํ์ธํ๋๊ฐ?
โก ์ธ๋ฑ์ค ์ฌ์ฉ๋ฅ ์ ๋ชจ๋ํฐ๋งํ๋๊ฐ?
โก ๋ฐ์ดํฐ๋ฒ ์ด์ค CPU, ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ฅ ์ ์ฒดํฌํ๋๊ฐ?
โก ์ปค๋ฅ์
ํ ์ค์ ์ด ์ ์ ํ๊ฐ?
โก ์บ์ ํํธ์จ์ ์ธก์ ํ๋๊ฐ?
โก ์ ๊ธฐ์ ์ผ๋ก ์ธ๋ฑ์ค ํต๊ณ๋ฅผ ์
๋ฐ์ดํธํ๋๊ฐ?
โก ์ธ๋ฑ์ค ๋จํธํ๋ฅผ ๊ด๋ฆฌํ๋๊ฐ?
๐จ ๋ฌธ์ ๋ฐ์ ์ ๋์ ์ฒดํฌ๋ฆฌ์คํธ
โก ์ด๋ค ์ฟผ๋ฆฌ๊ฐ ๋๋ฆฐ์ง ์๋ณํ๋๊ฐ?
โก EXPLAIN์ผ๋ก ์คํ ๊ณํ์ ๋ถ์ํ๋๊ฐ?
โก ์ธ๋ฑ์ค๊ฐ ์ ๋๋ก ์ฌ์ฉ๋๊ณ ์๋๊ฐ?
โก ๋ฐ์ดํฐ ์์ด ๊ธ์ฆํ๋๊ฐ?
โก ํ
์ด๋ธ ์ ๊ธ์ด ๋ฐ์ํ๋๊ฐ?
โก ๋คํธ์ํฌ ์ง์ฐ์ ์๋๊ฐ?
โก ์ ํ๋ฆฌ์ผ์ด์
๋ ๋ฒจ ์บ์ฑ์ ๊ณ ๋ คํ๋๊ฐ?
โก ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์กฐ ๊ฐ์ ์ด ํ์ํ๊ฐ?
๐ก ๋ง์น๋ฉฐ
์, ์ฌ๊ธฐ๊น์ง ์ ๋ง ๊ธด ์ฌ์ ์ด์์ด! ๐ ์ธ๋ฑ์ค์ ์ฟผ๋ฆฌ ์ต์ ํ์ ๋ํด ๊ธฐ๋ณธ๋ถํฐ ๊ณ ๊ธ ๊ธฐ๋ฒ๊น์ง ํจ๊ป ์ดํด๋ดค์ด. ์ด์ ์ ๋ฆฌ๋ฅผ ํด๋ณผ๊น?
๐ฏ ํต์ฌ ์์ฝ
1. ์ธ๋ฑ์ค๋ ๊ฒ์ ์ฑ๋ฅ์ ํต์ฌ
B-Tree ๊ตฌ์กฐ๋ก O(log n) ์๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฐพ์ ์ ์์ด. ์ฑ
์ ์์ธ๊ณผ ๊ฐ์ ์๋ฆฌ์ผ.
2. ์ ์ ํ ์ธ๋ฑ์ค ์ค๊ณ๊ฐ ์ค์
WHERE, JOIN, ORDER BY์ ์์ฃผ ์ฌ์ฉ๋๋ ์ปฌ๋ผ์ ์ธ๋ฑ์ค๋ฅผ ๋ง๋ค๋, ๋๋ฌด ๋ง์ผ๋ฉด ์คํ๋ ค ๋
์ด ๋ผ. ์นด๋๋๋ฆฌํฐ์ ์ฌ์ฉ ํจํด์ ๊ณ ๋ คํด์ผ ํด.
3. ์ฟผ๋ฆฌ ์์ฑ ๋ฐฉ๋ฒ์ด ์ฑ๋ฅ์ ์ข์ฐ
์ธ๋ฑ์ค ์ปฌ๋ผ์ ํจ์ ์ฌ์ฉ ๊ธ์ง, LIKE ํจํด ์ฃผ์, ํ์ํ ์ปฌ๋ผ๋ง SELECT, ์ ์ ํ JOIN ํ์
์ ํ ๋ฑ์ด ์ค์ํด.
4. EXPLAIN์ผ๋ก ํญ์ ํ์ธ
์คํ ๊ณํ์ ๋ณด๋ฉด ์ฟผ๋ฆฌ๊ฐ ์ด๋ป๊ฒ ๋์ํ๋์ง ์ ์ ์์ด. Full Table Scan์ ํผํ๊ณ ์ธ๋ฑ์ค๋ฅผ ์ ๋๋ก ํ์ฉํ๋์ง ์ฒดํฌํ์.
5. ์ง์์ ์ธ ๋ชจ๋ํฐ๋ง๊ณผ ๊ด๋ฆฌ
ํ ๋ฒ ์ต์ ํํ๊ณ ๋์ด ์๋์ผ. ๋ฐ์ดํฐ๊ฐ ๋ณํ๊ณ ์ฌ์ฉ ํจํด์ด ๋ฐ๋๋ฉด ์ฑ๋ฅ๋ ๋ฌ๋ผ์ ธ. ์ ๊ธฐ์ ์ผ๋ก ์ ๊ฒํ๊ณ ๊ฐ์ ํด์ผ ํด.
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฑ๋ฅ ์ต์ ํ๋ ๊ณผํ์ด์ ์์ ์ด์ผ. ์ด๋ก ์ ์ธ ์ง์๋ ์ค์ํ์ง๋ง, ์ค์ ๋ฐ์ดํฐ์ ์ฟผ๋ฆฌ ํจํด์ ๋ถ์ํ๊ณ ํ ์คํธํ๋ฉด์ ๊ฒฝํ์ ์๋ ๊ฒ ๋ ์ค์ํด. ๐จ
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์ ์ด์ํ๋ , ์์ ๊ฐ์ธ ํ๋ก์ ํธ๋ฅผ ํ๋ , ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฑ๋ฅ์ ์ฌ์ฉ์ ๊ฒฝํ์ ์ง์ ์ ์ธ ์ํฅ์ ์ค. ๋ช ์ด ์ฐจ์ด๊ฐ ์ฌ์ฉ์์ ์ดํ์ ๊ฒฐ์ ํ ์ ์๊ฑฐ๋ . ๐
๐ ๋ค์ ๋จ๊ณ๋ก
์ด ๊ธ์์ ๋ฐฐ์ด ๋ด์ฉ์ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํด๋ณด์! ์์ ๊ฒ๋ถํฐ ์์ํด:
1. ํ์ฌ ํ๋ก์ ํธ์ ์ฌ๋ก์ฐ ์ฟผ๋ฆฌ๋ฅผ ์ฐพ์๋ณด๊ธฐ
2. EXPLAIN์ผ๋ก ์คํ ๊ณํ ๋ถ์ํ๊ธฐ
3. ์ ์ ํ ์ธ๋ฑ์ค ์ถ๊ฐํ๊ธฐ
4. ์ฑ๋ฅ ๊ฐ์ ์ ํ๋ฅผ ์ธก์ ํ๊ณ ๋น๊ตํ๊ธฐ
5. ํ์๋ค๊ณผ ๊ฒฐ๊ณผ ๊ณต์ ํ๊ธฐ
์์ ์ฑ๊ณต ๊ฒฝํ์ด ์์ด๋ฉด ์ ์ ๋ ๋ณต์กํ ์ต์ ํ๋ ์์ ๊ฐ ์๊ฒ ํ ์ ์์ ๊ฑฐ์ผ! ๐ช
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ต์ ํ๋ ๋์ด ์๋ ์ฌ์ ์ด์ผ. ํญ์ ๋ ๋์ ๋ฐฉ๋ฒ์ด ์๊ณ , ์๋ก์ด ๊ธฐ์ ์ด ๋์ค๊ณ , ๋ ํจ์จ์ ์ธ ํจํด์ด ๋ฐ๊ฒฌ๋์ง. ํ์ง๋ง ์ด ๊ธ์์ ๋ฐฐ์ด ๊ธฐ๋ณธ ์์น๋ค์ ๋ณํ์ง ์์. ์ด ์์น๋ค์ ์ ์ดํดํ๊ณ ์๋ค๋ฉด, ์ด๋ค ์ํฉ์์๋ ์ฌ๋ฐ๋ฅธ ํ๋จ์ ๋ด๋ฆด ์ ์์ ๊ฑฐ์ผ! ๐
ํน์ ์ค๋ฌด์์ ์ฑ๋ฅ ๋ฌธ์ ๋ก ๊ณ ๋ฏผํ๊ณ ์๋ค๋ฉด, ์ฌ๋ฅ๋ท์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๋ฌธ๊ฐ๋ค์ ๋์์ ๋ฐ์๋ณผ ์๋ ์์ด. ๋๋ก๋ ๊ฒฝํ ๋ง์ ์ ๋ฌธ๊ฐ์ ์กฐ์ธ ํ๋ง๋๊ฐ ๋ฉฐ์น ๊ฐ์ ๊ณ ๋ฏผ์ ๋จ๋ฒ์ ํด๊ฒฐํด์ฃผ๊ธฐ๋ ํ๊ฑฐ๋ ! ๐
์, ์ด์ ๋น์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ ๋ ตํ๊ฒ ๋ง๋ค์ด๋ณผ ์๊ฐ์ด์ผ! ํ์ด์ ๋น์ด! ๐
Happy Optimizing! ๐โจ
๋น ๋ฅธ ์ฟผ๋ฆฌ, ํ๋ณตํ ์ฌ์ฉ์, ์ฑ๊ณต์ ์ธ ์๋น์ค!
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.