์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ ์ธ๋ฑ์Šค ์ตœ์ ํ™”์™€ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ ๊ฐœ์„  ๋ฐฉ๋ฒ•

๐Ÿš€ ์ธ๋ฑ์Šค ์ตœ์ ํ™”์™€ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ ๊ฐœ์„  ๋ฐฉ๋ฒ•

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ฑ๋Šฅ์„ ํญ๋ฐœ์ ์œผ๋กœ ๋Œ์–ด์˜ฌ๋ฆฌ๋Š” ์‹ค์ „ ๊ฐ€์ด๋“œ

์•ˆ๋…•! ์˜ค๋Š˜์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ๋ˆ„๊ตฌ๋‚˜ ํ•œ ๋ฒˆ์ฏค ๊ณ ๋ฏผํ•˜๊ฒŒ ๋˜๋Š” ์ฃผ์ œ๋ฅผ ๊ฐ€์ง€๊ณ  ์™”์–ด. ๋ฐ”๋กœ ์ธ๋ฑ์Šค ์ตœ์ ํ™”์™€ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ ๊ฐœ์„ ์ด์•ผ. ๐Ÿ˜Š

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

์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ํ•ต์‹ฌ ์—ด์‡ ๊ฐ€ ๋ฐ”๋กœ ์ธ๋ฑ์Šค์•ผ. ์ธ๋ฑ์Šค๋ฅผ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๊ณ  ํ™œ์šฉํ•˜๋ฉด ์ฟผ๋ฆฌ ์„ฑ๋Šฅ์„ ์ˆ˜์‹ญ ๋ฐฐ, ์‹ฌ์ง€์–ด ์ˆ˜๋ฐฑ ๋ฐฐ๊นŒ์ง€ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์–ด. ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ๋„ ์ˆ˜๋งŽ์€ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ์™€ ๊ฑฐ๋ž˜ ์ •๋ณด๋ฅผ ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด ์ธ๋ฑ์Šค ์ตœ์ ํ™”๊ฐ€ ํ•„์ˆ˜์ ์ด์ง€.

๊ทธ๋Ÿผ ์ง€๊ธˆ๋ถ€ํ„ฐ ์ธ๋ฑ์Šค์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹ค์ „ ์ตœ์ ํ™” ๊ธฐ๋ฒ•๊นŒ์ง€, ์นœ๊ตฌ์—๊ฒŒ ์„ค๋ช…ํ•˜๋“ฏ ํŽธํ•˜๊ฒŒ ํ’€์–ด๋ณผ๊ฒŒ! ๐Ÿ“š

์ธ๋ฑ์Šค์˜ ๋งˆ๋ฒ• ์ธ๋ฑ์Šค ์—†์ด ์ „์ฒด ์Šค์บ” ๋А๋ฆผ ๐Ÿข 10์ดˆ ์ธ๋ฑ์Šค ํ™œ์šฉ ์ง์ ‘ ์ ‘๊ทผ ๋น ๋ฆ„ ๐Ÿš€ 0.01์ดˆ

๐Ÿ“– ์ธ๋ฑ์Šค๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

์ธ๋ฑ์Šค๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ์ฑ…์˜ ์ƒ‰์ธ์„ ๋– ์˜ฌ๋ฆฌ๋Š” ๊ฑฐ์•ผ. ๋‘๊บผ์šด ๋ฐฑ๊ณผ์‚ฌ์ „์—์„œ ํŠน์ • ๋‹จ์–ด๋ฅผ ์ฐพ๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ด. ์ƒ‰์ธ ์—†์ด ์ฒซ ํŽ˜์ด์ง€๋ถ€ํ„ฐ ๋๊นŒ์ง€ ๋„˜๊ธฐ๋ฉด์„œ ์ฐพ์œผ๋ฉด ์–ผ๋งˆ๋‚˜ ์˜ค๋ž˜ ๊ฑธ๋ฆด๊นŒ? ๐Ÿ˜ฐ

ํ•˜์ง€๋งŒ ๋’ค์ชฝ์— ์žˆ๋Š” ์ƒ‰์ธ์„ ๋ณด๋ฉด "๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค โ†’ 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์ผ๊นŒ์ง€"๊ฐ™์€ ๋ฒ”์œ„ ์กฐ๊ฑด์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ์—„์ฒญ ๋น ๋ฅด์ง€! ๐Ÿ“…

B-Tree ๊ตฌ์กฐ Root Node 50 Branch 25 Branch 75 Leaf 10, 15, 20 Leaf 30, 35, 40 Leaf 60, 65, 70 Leaf 80, 85, 90 ๊ฒ€์ƒ‰ ๊ฒฝ๋กœ ์˜ˆ์‹œ: ๊ฐ’ 35 ์ฐพ๊ธฐ โ‘  โ‘ก โ‘ข ๋‹จ 3๋‹จ๊ณ„๋งŒ์— ๋ฐ์ดํ„ฐ ๋ฐœ๊ฒฌ! O(log n) ์‹œ๊ฐ„ ๋ณต์žก๋„ ๐Ÿš€

๐ŸŽจ ์ธ๋ฑ์Šค์˜ ์ข…๋ฅ˜

์ธ๋ฑ์Šค์—๋„ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜๊ฐ€ ์žˆ์–ด. ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ์ธ๋ฑ์Šค๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•˜์ง€. ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณผ๊นŒ? ๐Ÿ”Ž

ํด๋Ÿฌ์Šคํ„ฐ๋“œ ์ธ๋ฑ์Šค (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. ์ธก์ • Measure 2. ๋ถ„์„ Analyze 3. ์ตœ์ ํ™” Optimize 4. ๊ฒ€์ฆ Verify 5. ๋ชจ๋‹ˆํ„ฐ๋ง Monitor ์ธก์ • ๋„๊ตฌ EXPLAIN Slow Query Log Performance Schema ์ตœ์ ํ™” ๊ธฐ๋ฒ• ์ธ๋ฑ์Šค ์ถ”๊ฐ€ ์ฟผ๋ฆฌ ๊ฐœ์„  ๊ตฌ์กฐ ๋ณ€๊ฒฝ ์ง€์†์ ์ธ ๊ฐœ์„  ์‚ฌ์ดํด ๐Ÿ”„

๐Ÿ’ก ๋งˆ์น˜๋ฉฐ

์™€, ์—ฌ๊ธฐ๊นŒ์ง€ ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์–ด! ๐ŸŽ‰ ์ธ๋ฑ์Šค์™€ ์ฟผ๋ฆฌ ์ตœ์ ํ™”์— ๋Œ€ํ•ด ๊ธฐ๋ณธ๋ถ€ํ„ฐ ๊ณ ๊ธ‰ ๊ธฐ๋ฒ•๊นŒ์ง€ ํ•จ๊ป˜ ์‚ดํŽด๋ดค์–ด. ์ด์ œ ์ •๋ฆฌ๋ฅผ ํ•ด๋ณผ๊นŒ?

๐ŸŽฏ ํ•ต์‹ฌ ์š”์•ฝ

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
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.