Skip to content

Latest commit

ย 

History

History
1378 lines (1146 loc) ยท 93 KB

File metadata and controls

1378 lines (1146 loc) ยท 93 KB

์˜ตํ‹ฐ๋งˆ์ด์ €์™€ ํžŒํŠธ

  • ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ์ฟผ๋ฆฌ์˜ ์‹คํ–‰ ๊ณ„ํš์„ ์ˆ˜๋ฆฝํ•˜๋Š” ๋ถ€๋ถ„์œผ๋กœ ๊ฐ€์žฅ ๋ณต์žกํ•˜๋‹ค.
  • MySQL์—์„œ๋Š” EXPLAIN์ด๋ผ๋Š” ๋ช…๋ น์œผ๋กœ ์ฟผ๋ฆฌ์˜ ์‹คํ–‰ ๊ณ„ํš์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. (์ƒ๋‹นํžˆ ๋งŽ์€ ์ •๋ณด๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.)

1. ๊ฐœ์š”

1-1. ์ฟผ๋ฆฌ ์‹คํ–‰ ์ ˆ์ฐจ

  • MySQL์—์„œ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ณผ์ •์€ ์•„๋ž˜ ์„ธ ๋‹จ๊ณ„์ด๋‹ค.
  1. SQL ํŒŒ์‹ฑ
    • ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ์š”์ฒญ๋œ SQL ๋ฌธ์žฅ์„ ์ž˜๊ฒŒ ์ชผ๊ฐœ์„œ MySQL ์„œ๋ฒ„๊ฐ€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜์ค€์œผ๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค.
    • SQL ํŒŒ์„œ๋ผ๋Š” ๋ชจ๋“ˆ๋กœ SQL ๋ฌธ์žฅ์„ ํŒŒ์‹ฑํ•œ๋‹ค.
    • ์ด ๋‹จ๊ณ„๋ฅผ ํ†ตํ•ด SQL ํŒŒ์Šค ํŠธ๋ฆฌ๊ฐ€ ๋งŒ๋“ค์–ด์ง€๊ณ  ํŒŒ์Šค ํŠธ๋ฆฌ๋ฅผ ํ†ตํ•ด ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
  2. ์ตœ์ ํ™” ๋ฐ ์‹คํ–‰ ๊ณ„ํš ์ˆ˜๋ฆฝ
    • SQL์˜ ํŒŒ์‹ฑ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๋ฉด์„œ ์–ด๋–ค ํ…Œ์ด๋ธ”๋ถ€ํ„ฐ ์ฝ๊ณ  ์–ด๋–ค ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•ด ํ…Œ์ด๋ธ”์„ ์ฝ์„์ง€ ๊ฒฐ์ •ํ•œ๋‹ค.
    • SQL ํŒŒ์Šค ํŠธ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  3. ์‹คํ–‰ ๊ณ„ํš๋Œ€๋กœ ์ž‘์—… ์ˆ˜ํ–‰
    • ๋‘ ๋ฒˆ์งธ ๋‹จ๊ณ„์—์„œ ๊ฒฐ์ •๋œ ํ…Œ์ด๋ธ”์˜ ์ฝ๊ธฐ ์ˆœ์„œ๋‚˜ ์„ ํƒ๋œ ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•ด ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์œผ๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
  • 2๋ฒˆ์งธ ๋‹จ๊ณ„์ธ "์ตœ์ ํ™” ๋ฐ ์‹คํ–‰ ๊ณ„ํš ์ˆ˜๋ฆฝ"์€ ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„์—์„œ ๋งŒ๋“ค์–ด์ง„ SQL ํŒŒ์Šค ํŠธ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•˜๋ฉด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‚ด์šฉ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ๋ถˆํ•„์š”ํ•œ ์กฐ๊ฑด ์ œ๊ฑฐ ๋ฐ ๋ณต์žกํ•œ ์—ฐ์‚ฐ์˜ ๋‹จ์ˆœํ™”
    • ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์˜ ์กฐ์ธ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์–ด๋–ค ์ˆœ์„œ๋กœ ํ…Œ์ด๋ธ”์„ ์ฝ์„์ง€ ๊ฒฐ์ •
    • ๊ฐ ํ…Œ์ด๋ธ”์— ์‚ฌ์šฉ๋œ ์กฐ๊ฑด๊ณผ ์ธ๋ฑ์Šค ํ†ต๊ณ„ ์ •๋ณด๋ฅผ ์ด์šฉํ•ด ์‚ฌ์šฉํ•  ์ธ๋ฑ์Šค๋ฅผ ๊ฒฐ์ •
    • ๊ฐ€์ ธ์˜จ ๋ ˆ์ฝ”๋“œ๋“ค์„ ์ž„์‹œ ํ…Œ์ด๋ธ”์— ๋„ฃ๊ณ  ๋‹ค์‹œ ํ•œ ๋ฒˆ ๊ฐ€๊ณตํ•ด์•ผ ํ•˜๋Š”์ง€ ๊ฒฐ์ •
  • ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„์™€ ๋‘ ๋ฒˆ์งธ ๋‹จ๊ณ„๋Š” ๊ฑฐ์˜ MySQL ์—”์ง„์—์„œ ์ฒ˜๋ฆฌํ•˜๋ฉฐ, ์„ธ ๋ฒˆ์งธ ๋‹จ๊ณ„๋Š” MySQL ์—”์ง„๊ณผ ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์ด ๋™์‹œ์— ์ฐธ์—ฌํ•ด์„œ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ๋‘ ๋ฒˆ์งธ ๋‹จ๊ณ„๋Š” ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ์ฒ˜๋ฆฌ

<br/ >

1-2. ์˜ตํ‹ฐ๋งˆ์ด์ €์˜ ์ข…๋ฅ˜

  • ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋‘๋‡Œ ์—ญํ• 
  • ๋Œ€๋ถ€๋ถ„์˜ DBMS์—์„œ๋Š” ๋น„์šฉ ๊ธฐ๋ฐ˜ ์ตœ์ ํ™• Cost-Based Optimizer, CBO ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • ์˜ˆ์ „์— ์˜ค๋ผํด์—์„œ ๋งŽ์ด ์‚ฌ์šฉํ–ˆ๋˜ ๊ทœ์น™ ๊ธฐ๋ฐ˜ ์ตœ์ ํ™” Rule-Based Optimizer ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค.

๋น„์šฉ ๊ธฐ๋ฐ˜ ์ตœ์ ํ™”

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

๊ทœ์น™ ๊ธฐ๋ฐ˜ ์ตœ์ ํ™”

  • ์ด์ œ ๊ฑฐ์˜ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋ฐฉ๋ฒ•
  • ์˜ตํ‹ฐ๋งˆ์ด์ €์— ๋‚ด์žฅ๋œ ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์‹คํ–‰ ๊ณ„ํš์„ ์ˆ˜๋ฆฝํ•˜๋Š” ๋ฐฉ์‹
  • ํ†ต๊ณ„ ์ •๋ณด(ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜, ์นผ๋Ÿผ๊ฐ’์˜ ๋ถ„ํฌ๋„)๋ฅผ ์กฐ์‚ฌํ•˜์ง€ ์•Š๊ณ  ์‹คํ–‰ ๊ณ„ํš์ด ์ˆ˜๋ฆฝ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ™์€ ์ฟผ๋ฆฌ์— ๋Œ€ํ•ด์„œ ๊ฑฐ์˜ ํ•ญ์ƒ ๊ฐ™์€ ๋ฐฉ๋ฒ• ์‹คํ–‰ ๋ฐฉ๋ฒ•์„ ๋งŒ๋“ค์–ด๋‚ธ๋‹ค.

<br/ >

2. ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ

  • ๊ธฐ๋ณธ์ ์œผ๋กœ ์ •๋ ฌ ๋ฐ ๊ทธ๋ฃจํ•‘ ๋“ฑ์˜ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ๊ฐ€๊ณต ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ๊ฒฐ๊ณผ๋ฌผ์€ ๋™์ผํ•˜๋”๋ผ๋„ RDBMS๋ณ„๋กœ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค์–ด ๋‚ด๋Š” ๊ณผ์ •์€ ์ฒœ์ฐจ๋งŒ๋ณ„์ด๋‹ค.

2-1. ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”

  • ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์กฐ๊ฑด์ผ ๋•Œ ์ฃผ๋กœ ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์„ ์„ ํƒํ•œ๋‹ค.
    • ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ์ž‘์•„์„œ ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•ด ์ฝ๋Š” ๊ฒƒ๋ณด๋‹ค ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์„ ํ•˜๋Š” ํŽธ์ด ๋” ๋น ๋ฅธ ๊ฒฝ์šฐ (์ผ๋ฐ˜์ ์œผ๋กœ ํ…Œ์ด๋ธ”์ด ํŽ˜์ด์ง€ 1๊ฐœ๋กœ ๊ตฌ์„ฑ๋œ ๊ฒฝ์šฐ)
    • WHERE ์ ˆ์ด๋‚˜ ON ์ ˆ์— ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ ์ ˆํ•œ ์กฐ๊ฑด์ด ์—†๋Š” ๊ฒฝ์šฐ
    • ์ธ๋ฑ์Šค ๋ ˆ์ธ์ง€ ์Šค์บ”์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ฟผ๋ฆฌ๋ผ๊ณ  ํ•˜๋”๋ผ๋„ ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ํŒ๋‹จํ•œ ์กฐ๊ฑด ์ผ์น˜ ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์€ ๊ฒฝ์šฐ (์ธ๋ฑ์Šค์˜ B-Tree๋ฅผ ์ƒ˜ํ”Œ๋งํ•ด์„œ ์กฐ์‚ฌํ•œ ํ†ต๊ณ„ ์ •๋ณด ๊ธฐ์ค€)
  • ๋Œ€๋ถ€๋ถ„์˜ DBMS๋Š” ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์„ ์‹คํ–‰ํ•  ๋•Œ ํ•œ๊บผ๋ฒˆ์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ธ”๋ก์ด๋‚˜ ํŽ˜์ด์ง€๋ฅผ ์ฝ์–ด์˜ค๋Š” ๊ธฐ๋Šฅ์„ ๋‚ด์žฅํ•˜๊ณ  ์žˆ๋‹ค.
    • ํ•˜์ง€๋งŒ MySQL์—๋Š” ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์„ ์‹คํ–‰ํ•  ๋•Œ ํ•œ๊บผ๋ฒˆ์— ๋ช‡ ๊ฐœ์”ฉ ํŽ˜์ด์ง€๋ฅผ ์ฝ์–ด์˜ฌ์ง€ ์„ค์ •ํ•˜๋Š” ์‹œ์Šคํ…œ ๋ณ€์ˆ˜๋Š” ์—†๋‹ค.
    • ๊ทธ๋ž˜์„œ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด MySQL์€ ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์„ ์‹คํ–‰ํ•  ๋•Œ ๋””์Šคํฌ๋กœ๋ถ€ํ„ฐ ํŽ˜์ด์ง€๋ฅผ ํ•˜๋‚˜์”ฉ ์ฝ์–ด ์˜จ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์€ ์ฐฉ๊ฐ์ด๋‹ค.
  • MyISAM์—์„œ ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์„ ํ•  ๋•Œ๋Š” ๋””์Šคํฌ๋กœ๋ถ€ํ„ฐ ํŽ˜์ด์ง€๋ฅผ ํ•˜๋‚˜์”ฉ ์ฝ์–ด์˜ค์ง€๋งŒ InnoDB์˜ ์ž‘๋™ ๋ฐฉ์‹์€ ์•ฝ๊ฐ„ ๋‹ค๋ฅด๋‹ค.
    • InnoDB ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์€ ํŠน์ • ํ…Œ์ด๋ธ”์˜ ์—ฐ์†๋œ ๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€๊ฐ€ ์ฝํžˆ๋ฉด ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ์— ์˜ํ•ด ๋ฆฌ๋“œ ์–ดํ—ค๋“œ Read ahead ์ž‘์—…์ด ์ž๋™์œผ๋กœ ์‹œ์ž‘๋œ๋‹ค.
    • ์—ฌ๊ธฐ์„œ ๋ฆฌ๋“œ ์–ดํ—ค๋“œ๋ž€ ์–ด๋–ค ์˜์—ญ์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ์•ž์œผ๋กœ ํ•„์š”ํ•ด์ง€๋ฆฌ๋ผ๋Š” ๊ฒƒ์„ ์˜ˆ์ธกํ•ด์„œ ์š”์ฒญ์ด ์˜ค๊ธฐ ์ „์— ๋ฏธ๋ฆฌ ๋””์Šคํฌ์—์„œ ์ฝ์–ด InnoDB์˜ ๋ฒ„ํผ ํ’€์— ๊ฐ€์ ธ๋‹ค ๋‘๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
    • ์ฆ‰, ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์ด ์‹คํ–‰๋˜๋ฉด ์ฒ˜์Œ ๋ช‡ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€๋Š” ํฌ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ (Foreground thread, ํด๋ผ์ด์–ธํŠธ ์Šค๋ ˆ๋“œ)๊ฐ€ ํŽ˜์ด์ง€ ์ฝ๊ธฐ๋ฅผ ์‹คํ–‰ํ•˜์ง€๋งŒ, ํŠน์ • ์‹œ์ ๋ถ€ํ„ฐ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ๋กœ ๋„˜๊ธด๋‹ค.
    • ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ๊ฐ€ ์ฝ๊ธฐ๋ฅผ ๋„˜๊ฒจ๋ฐ›์œผ๋ฉด ํ•œ ๋ฒˆ์— 4๊ฐœ ๋˜๋Š” 8๊ฐœ์”ฉ ํŽ˜์ด์ง€๋ฅผ ์ฝ์œผ๋ฉด์„œ ๊ณ„์† ๊ทธ ์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค. ์ด ๋•Œ ํ•œ ๋ฒˆ์— ์ตœ๋Œ€ 64๊ฐœ์˜ ๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€๊นŒ์ง€ ์ฝ์–ด์„œ ๋ฒ„ํผ ํ’€์— ์ €์žฅํ•ด๋‘”๋‹ค.
    • ํฌ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ๋Š” ๋ฒ„ํผ ํ’€์— ์ค€๋น„๋œ ๋ฐ์ดํ„ฐ๋งŒ ๊ฐ€์ ธ๋‹ค ์‚ฌ์šฉํ•˜๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ฟผ๋ฆฌ๊ฐ€ ์ƒ๋‹นํžˆ ๋นจ๋ฆฌ ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ์ด๋‹ค.
  • innodb_read_ahead_threshold๋ผ๋Š” ์‹œ์Šคํ…œ ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•ด ๋ฆฌ๋“œ ์–ดํ—ค๋“œ๋ฅผ ์–ธ์ œ ์‹œ์ž‘ํ• ์ง€ ์ž„๊ณ„๊ฐ’์„ ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ผ๋ฐ˜์ ์œผ๋กœ ๋””ํดํŠธ ์„ค์ •์œผ๋กœ๋„ ์ถฉ๋ถ„ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ ์›จ์–ดํ•˜์šฐ์Šค์šฉ์œผ๋กœ MySQL์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์ด ์˜ต์…˜์„ ๋” ๋‚ฎ์€ ๊ฐ’์œผ๋กœ ์„ค์ •ํ•ด์„œ ๋” ๋นจ๋ฆฌ ๋ฆฌ๋“œ ์–ดํ—ค๋“œ๊ฐ€ ์‹œ์ž‘๋˜๊ฒŒ ์œ ๋„ํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค.
  • ๋ฆฌ๋“œ ์–ดํ—ค๋“œ๋Š” ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํ’€ ์ธ๋ฑ์Šค ์Šค์บ”์—์„œ๋„ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉ๋œ๋‹ค.

2-2. ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ

  • MySQL 8.0๋ถ€ํ„ฐ ์ฒ˜์Œ์œผ๋กœ ์ฟผ๋ฆฌ์˜ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ด์กŒ๋‹ค.

์ฃผ์˜

  • ์—ฌ๊ธฐ์„œ ๋งํ•˜๋Š” ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋Š” ํ•˜๋‚˜์˜ ์ฟผ๋ฆฌ๋ฅผ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ์ž‘์—…์„ ๋‚˜๋ˆ„์–ด ๋™์‹œ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
  • ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ฟผ๋ฆฌ๋ฅผ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์€ MySQL๊ฐ€ ์ฒ˜์Œ ๋งŒ๋“ค์–ด์งˆ ๋•Œ๋ถ€ํ„ฐ ๊ฐ€๋Šฅํ–ˆ๋‹ค.
  • innodb_parallel_read_threads๋ผ๋Š” ์‹œ์Šคํ…œ ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•ด ํ•˜๋‚˜์˜ ์ฟผ๋ฆฌ๋ฅผ ์ตœ๋Œ€ ๋ช‡ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์ฒ˜๋ฆฌํ• ์ง€๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ•˜์ง€๋งŒ ์•„์ง MySQL ์„œ๋ฒ„์—์„œ๋Š” ์ฟผ๋ฆฌ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์ด์šฉํ•ด ๋ณ‘๋Ÿด๋กœ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ํ•˜๋Š” ํžŒํŠธ๋‚˜ ์˜ต์…˜์€ ์—†๋‹ค.
mysql> SET SESSION innodb_parallel_read_threads=1;
mysql> SELECT COUNT(*) FROM salaries;
1 row in set (0.81 sec)

# ์ด ์ˆœ๊ฐ„๋ถ€ํ„ฐ ์ฟผ๋ฆฌ๊ฐ€ ๊ฐœ์„ ๋˜์ง€ ์•Š๋Š”๋‹ค.
mysql> SET SESSION innodb_parallel_read_threads=2;
mysql> SELECT COUNT(*) FROM salaries;
1 row in set (0.19 sec)

mysql> SET SESSION innodb_parallel_read_threads=4;
mysql> SELECT COUNT(*) FROM salaries;
1 row in set (0.19 sec)

mysql> SET SESSION innodb_parallel_read_threads=8;
mysql> SELECT COUNT(*) FROM salaries;
1 row in set (0.19 sec)
  • ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์šฉ ์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚ ์ˆ˜๋ก ์ฟผ๋ฆฌ ์ฒ˜๋ฆฌ์— ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„์ด ์ค„์–ด๋“ ๋‹ค๊ณ  ํ•˜๋‚˜, ์„œ๋ฒ„์— ์žฅ์ฐฉ๋œ CPI์˜ ์ฝ”์–ด ๊ฐœ์ˆ˜๋ฅผ ๋„˜์–ด๊ฐ€๋ฉด ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์ด ์•ˆ ์ข‹์•„์ง„๋‹ค๊ณ  ํ•œ๋‹ค.

2-3. ORDER BY ์ฒ˜๋ฆฌ (Using Filesort)

  • ์ •๋ ฌ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋  ๋•Œ Filesort๋ผ๋Š” ๋ณ„๋„์˜ ์ฒ˜๋ฆฌ๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค.
์žฅ์  ๋‹จ์ 
์ธ๋ฑ์Šค ์ด์šฉ INSERT, UPDATE, DELETE ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋  ๋•Œ ์ด๋ฏธ ์ธ๋ฑ์Šค๊ฐ€ ์ •๋ ฌ๋˜์–ด ์žˆ์–ด์„œ ์ˆœ์„œ๋Œ€๋กœ ์ฝ๊ธฐ๋งŒ ํ•˜๋ฉด ๋˜๋ฏ€๋กœ ๋งค์šฐ ๋น ๋ฅด๋‹ค. INSERT, UPDATE, DELETE ์ž‘์—… ์‹œ ๋ถ€๊ฐ€์ ์ธ ์ธ๋ฑ์Šค ์ถ”๊ฐ€/์‚ญ์ œ ์ž‘์—…์ด ํ•„์š”ํ•˜๋ฏ€๋กœ ๋А๋ฆฌ๋‹ค. ์ธ๋ฑ์Šค ๋•Œ๋ฌธ์— ๋””์Šคํฌ ๊ณต๊ฐ„์ด ๋” ๋งŽ์ด ํ•„์š”ํ•˜๋‹ค. ์ธ๋ฑ์Šค์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚ ์ˆ˜๋ก InnoDB์˜ ๋ฒ„ํผ ํ’€์„ ์œ„ํ•œ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋งŽ์ด ํ•„์š”ํ•˜๋‹ค.
Filesort ์ด์šฉ ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋˜๋ฏ€๋กœ ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•  ๋•Œ์˜ ๋‹จ์ ์ด ์žฅ์ ์œผ๋กœ ๋ฐ”๋€๋‹ค. ์ •๋ ฌํ•ด์•ผ ํ•  ๋ ˆ์ฝ”๋“œ๊ฐ€ ๋งŽ์ง€ ์•Š์œผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ์—์„œ Filesort๊ฐ€ ์ฒ˜๋ฆฌ๋˜๋ฏ€๋กœ ์ถฉ๋ถ„ํžˆ ๋น ๋ฅด๋‹ค. ์ •๋ ฌ ์ž‘์—…์ด ์ฟผ๋ฆฌ ์‹คํ–‰ ์‹œ ์ฒ˜๋ฆฌ๋˜๋ฏ€๋กœ ๋ ˆ์ฝ”๋“œ ๋Œ€์ƒ ๊ฑด์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ ์ˆ˜๋ก ์ฟผ๋ฆฌ์˜ ์‘๋‹ต ์†๋„๊ฐ€ ๋А๋ฆฌ๋‹ค.
  • ๋ฌผ๋ก  ๋ ˆ์ฝ”๋“œ๋ฅผ ์ •๋ ฌํ•˜๊ธฐ ์œ„ํ•ด ํ•ญ์ƒ "Filesort"๋ผ๋Š” ์ •๋ ฌ ์ž‘์—…์„ ๊ฑฐ์ณ์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•œ ์ •๋ ฌ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ํ•˜์ง€๋งŒ ์•„๋ž˜์™€ ๊ฐ™์€ ์ด์œ ๋กœ ๋ชจ๋“  ์ •๋ ฌ์„ ์ธ๋ฑ์Šค๋กœ ์ฒ˜๋ฆฌํ•ด ํŠœ๋‹ํ•˜๊ธฐ๋ž€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
    • ์ •๋ ฌ ๊ธฐ์ค€์ด ๋„ˆ๋ฌด ๋งŽ์•„์„œ ์š”๊ฑด๋ณ„๋กœ ๋ชจ๋‘ ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•  ๋•Œ
    • GROUP BY์˜ ๊ฒฐ๊ณผ ๋˜๋Š” DISTINCT ๊ฐ™์€ ์ฒ˜๋ฆฌ์˜ ๊ฒฐ๊ณผ๋ฅผ ์ •๋ ฌํ•ด์•ผํ•  ๋•Œ
    • UNION์˜ ๊ฒฐ๊ณผ์™€ ๊ฐ™์ด ์ž„์‹œ ํ…Œ์ด๋ธ”์˜ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ์ •๋ ฌํ•ด์•ผํ•  ๋•Œ
    • ๋žœ๋คํ•˜๊ฒŒ ๊ฒฐ๊ณผ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฐ€์ ธ์™€์•ผํ•  ๋•Œ
  • ๋ณ„๋„์˜ ์ •๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ–ˆ๋Š”์ง€๋Š” ์‹คํ–‰ ๊ณ„ํš์˜ Extra ์นผ๋Ÿผ์— "Using filesort" ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋˜๋Š”์ง€ ์—ฌ๋ถ€๋กœ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค.

2-3-1. ์†ŒํŠธ ๋ฒ„ํผ

  • MySQL์—์„œ๋Š” ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๋ณ„๋„์˜ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ํ• ๋‹น๋ฐ›์•„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ ์ด ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ์†ŒํŠธ ๋ฒ„ํผ Sort buffer๋ผ๊ณ  ํ•œ๋‹ค.
  • ์†ŒํŠธ ๋ฒ„ํผ๋Š” ์ •๋ ฌ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ํ• ๋‹น๋˜๋ฉฐ, ๋ฒ„ํผ์˜ ํฌ๊ธฐ๋Š” ์ •๋ ฌํ•ด์•ผ ํ•  ๋ ˆ์ฝ”๋“œ์˜ ํฌ๊ธฐ์— ๋”ฐ๋ผ ๊ฐ€๋ณ€์ ์œผ๋กœ ์ฆ๊ฐ€ํ•˜์ง€๋งŒ ์ตœ๋Œ€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์†ŒํŠธ ๋ฒ„ํผ์˜ ๊ณต๊ฐ„์€ sort_buffer_size๋ผ๋Š” ์‹œ์Šคํ…œ ๋ณ€์ˆ˜๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์€ ์ฟผ๋ฆฌ ์‹คํ–‰์ด ์™„๋ฃŒ๋˜๋ฉด ๋ฐ”๋กœ ๋ฐ˜๋‚ฉ๋œ๋‹ค.
  • ๊ทธ๋Ÿฐ๋ฐ ์ •๋ ฌ์ด ์™œ ๋ฌธ์ œ๊ฐ€ ๋ ๊นŒ?
    • ์ •๋ ฌํ•  ๋ ˆ์ฝ”๋“œ๊ฐ€ ์•„์ฃผ ์†Œ๋Ÿ‰์ด์–ด์„œ ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น๋œ ์†ŒํŠธ ๋ฒ„ํผ๋งŒ์œผ๋กœ ์ •๋ ฌํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์•„์ฃผ ๋น ๋ฅด๊ฒŒ ์ •๋ ฌ์ด ์ฒ˜๋ฆฌ๋  ๊ฒƒ์ด๋‹ค.
  • ํ•˜์ง€๋งŒ ์ •๋ ฌํ•ด์•ผ ํ•  ๋ ˆ์ฝ”๋“œ์˜ ๊ฑด์ˆ˜๊ฐ€ ์†ŒํŠธ ๋ฒ„ํผ๋กœ ํ• ๋‹น๋œ ๊ณต๊ฐ„๋ณด๋‹ค ํฌ๋‹ค๋ฉด ์–ด๋–จ๊นŒ?
    • ์ •๋ ฌํ•ด์•ผ ํ•  ๋ ˆ์ฝ”๋“œ์˜ ๊ฑด์ˆ˜๊ฐ€ ์†ŒํŠธ ๋ฒ„ํผ๋ณด๋‹ค ๋งŽ์•„์ง€๋ฉด ๋ ˆ์ฝ”๋“œ๋ฅผ ์—ฌ๋Ÿฌ ์กฐ๊ฐ์œผ๋กœ ๋‚˜๋ˆ  ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ์†ŒํŠธ ๋ฒ„ํผ์—์„œ ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋””์Šคํฌ์— ์ž„์‹œ๋กœ ์ €์žฅํ•ด๋‘”๋‹ค. ์ด๊ฒƒ์„ ๋ฐ˜๋ณตํ•œ๋‹ค.
    • ๊ฐ ๋ฒ„ํผ์˜ ํฌ๊ธฐ๋งŒํผ ์ •๋ ฌ๋œ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ๋ณ‘ํ•ฉํ•˜๋ฉด์„œ ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค. Multi-Merge ๋ฉ€ํ‹ฐ ๋จธ์ง€
    • ์ˆ˜ํ–‰๋œ ๋ฉ€ํ‹ฐ ๋จธ์ง€ ํšŸ์ˆ˜๋Š” Sort_merge_passes๋ผ๋Š” ์ƒํƒœ ๋ณ€์ˆ˜์— ๋ˆ„์ ํ•ด์„œ ์ง‘๊ณ„๋œ๋‹ค.
  • ์ด ์ž‘์—…๋“ค์ด ๋ชจ๋‘ ๋””์Šคํฌ์˜ ์“ฐ๊ธฐ์™€ ์ฝ๊ธฐ๋ฅผ ์œ ๋ฐœํ•˜๋ฉฐ, ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๊ฐ€ ๋งŽ์„์ˆ˜๋ก ์ด ๋ฐ˜๋ณต ์ž‘์—…์˜ ํšŸ์ˆ˜๊ฐ€ ๋งŽ์•„์ง„๋‹ค.
    • ์†ŒํŠธ ๋ฒ„ํผ๋ฅผ ํฌ๊ฒŒ ์„ค์ •ํ•˜๋ฉด ๋””์Šคํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์„œ ๋” ๋นจ๋ผ์งˆ ๊ฒƒ์œผ๋กœ ์ƒ๊ฐํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์‹ค์ œ ๋ฒค์น˜๋งˆํฌ ๊ฒฐ๊ณผ๋กœ๋Š” ํฐ ์ฐจ์ด๋ฅผ ๋ณด์ด์ง„ ์•Š์•˜๋‹ค.
    • 256KB ~ 8MB์—์„œ ์ตœ์ ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ž„.
    • ๋„ˆ๋ฌด ํฐ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์€ ์„ฑ๋Šฅ์„ ๋–จ์–ด๋œจ๋ฆฐ๋‹ค.
  • ํ•„์ž์— ์˜ํ•˜๋ฉด ์ ๋‹นํ•œ ์†ŒํŠธ๋ฒ„ํผ์˜ ํฌ๊ธฐ๋Š” 56KB์—์„œ 1MB ๋ฏธ๋งŒ ์ด๋ผ๊ณ  ํ•œ๋‹ค.
    • ์†ŒํŠธ ๋ฒ„ํผ๋Š” ์—ฌ๋Ÿฌ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ณต์œ ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์˜์—ญ์ด ์•„๋‹ˆ๋‹ค.
    • ์ปค๋„ฅ์…˜์ด ๋งŽ์œผ๋ฉด ๋งŽ์„์ˆ˜๋ก, ์ •๋ ฌ ์ž‘์—…์ด ๋งŽ์œผ๋ฉด ๋งŽ์„์ˆ˜๋ก ์†ŒํŠธ ๋ฒ„ํผ๋กœ ์†Œ๋น„๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์ด ์ปค์ง์„ ์˜๋ฏธํ•œ๋‹ค.

2-3-2. ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜

  • ๋ ˆ์ฝ”๋“œ ์ „์ฒด๋ฅผ ๋ฒ„ํผ์— ๋‹ด์„์ง€, ์ •๋ ฌ ๊ธฐ์ค€ ์นผ๋Ÿผ๋งŒ ์†ŒํŠธ ๋ฒ„ํผ์— ๋‹ด์„์ง€์— ๋”ฐ๋ผ ์‹ฑ๊ธ€ ํŒจ์Šค Single-Pass์™€ ํˆฌ ํŒจ์Šค Two-Pass 2๊ฐ€์ง€๋กœ ๋ชจ๋“œ๋ฅผ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค.
  • ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฟผ๋ฆฌ๊ฐ€ ์–ด๋–ค ์ •๋ ฌ ๋ชจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์˜ตํ‹ฐ๋งˆ์ด์ € ํŠธ๋ ˆ์ด์Šค ๊ธฐ๋Šฅ์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
mysql> SET OPTIMIZER_TRACE="enabled=on",END_MARKERS_IN_JSON=on;
mysql> SET OPTIMIZER_TRACE_MAX_MEM_SIZE=1000000;
  • ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•ด๋ณด์ž.
mysql> SELECT * FROM employees ORDER BY last_name LIMIT 100000, 1;
+--------+------------+------------+-----------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date  |
+--------+------------+------------+-----------+--------+------------+
| 418804 | 1958-01-06 | Jacopo     | Gyimothy  | F      | 1997-06-20 |
+--------+------------+------------+-----------+--------+------------+
1 row in set (0.21 sec)
  • ๊ทธ๋ฆฌ๊ณ  ํŠธ๋ ˆ์ด์…˜ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฌ๋ฉด ์˜ตํ‹ฐ๋งˆ์ด์ €์˜ ํŠธ๋ ˆ์ด์Šค ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
mysql> SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE \G
*************************** 1. row ***************************
                            QUERY: SELECT * FROM employees ORDER BY last_name LIMIT 100000, 1
                            TRACE: {
  "steps": [
    {
      "join_preparation": {
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `employees`.`emp_no` AS `emp_no`,`employees`.`birth_date` AS `birth_date`,`employees`.`first_name` AS `first_name`,`employees`.`last_name` AS `last_name`,`employees`.`gender` AS `gender`,`employees`.`hire_date` AS `hire_date` from `employees` order by `employees`.`last_name` limit 100000,1"
          }
        ] /* steps */
      } /* join_preparation */
    },
    {
      "join_optimization": {
        "select#": 1,
        "steps": [
          {
            "substitute_generated_columns": {
            } /* substitute_generated_columns */
          },
          {
            "table_dependencies": [
              {
                "table": "`employees`",
                "row_may_be_null": false,
                "map_bit": 0,
                "depends_on_map_bits": [
                ] /* depends_on_map_bits */
              }
            ] /* table_dependencies */
          },
          {
            "rows_estimation": [
              {
                "table": "`employees`",
                "table_scan": {
                  "rows": 300252,
                  "cost": 922.709
                } /* table_scan */
              }
            ] /* rows_estimation */
          },
          {
            "considered_execution_plans": [
              {
                "plan_prefix": [
                ] /* plan_prefix */,
                "table": "`employees`",
                "best_access_path": {
                  "considered_access_paths": [
                    {
                      "rows_to_scan": 300252,
                      "access_type": "scan",
                      "resulting_rows": 300252,
                      "cost": 30947.9,
                      "chosen": true
                    }
                  ] /* considered_access_paths */
                } /* best_access_path */,
                "condition_filtering_pct": 100,
                "rows_for_plan": 300252,
                "cost_for_plan": 30947.9,
                "chosen": true
              }
            ] /* considered_execution_plans */
          },
          {
            "attaching_conditions_to_tables": {
              "original_condition": null,
              "attached_conditions_computation": [
              ] /* attached_conditions_computation */,
              "attached_conditions_summary": [
                {
                  "table": "`employees`",
                  "attached": null
                }
              ] /* attached_conditions_summary */
            } /* attaching_conditions_to_tables */
          },
          {
            "optimizing_distinct_group_by_order_by": {
              "simplifying_order_by": {
                "original_clause": "`employees`.`last_name`",
                "items": [
                  {
                    "item": "`employees`.`last_name`"
                  }
                ] /* items */,
                "resulting_clause_is_simple": true,
                "resulting_clause": "`employees`.`last_name`"
              } /* simplifying_order_by */
            } /* optimizing_distinct_group_by_order_by */
          },
          {
            "finalizing_table_conditions": [
            ] /* finalizing_table_conditions */
          },
          {
            "refine_plan": [
              {
                "table": "`employees`"
              }
            ] /* refine_plan */
          },
          {
            "considering_tmp_tables": [
              {
                "adding_sort_to_table": "employees"
              } /* filesort */
            ] /* considering_tmp_tables */
          }
        ] /* steps */
      } /* join_optimization */
    },
    {
      "join_execution": {
        "select#": 1,
        "steps": [
          {
            "sorting_table": "employees",
            "filesort_information": [
              {
                "direction": "asc",
                "expression": "`employees`.`last_name`"
              }
            ] /* filesort_information */,
            "filesort_priority_queue_optimization": {
              "limit": 100001
            } /* filesort_priority_queue_optimization */,
            "filesort_execution": [
            ] /* filesort_execution */,
            "filesort_summary": {
              "memory_available": 262144,
              "key_size": 32,
              "row_size": 169,
              "max_rows_per_buffer": 1551,
              "num_rows_estimate": 300252,
              "num_rows_found": 300024,
              "num_initial_chunks_spilled_to_disk": 82,
              "peak_memory_used": 262144,
              "sort_algorithm": "std::stable_sort",
              "sort_mode": "<fixed_sort_key, packed_additional_fields>"
            } /* filesort_summary */
          }
        ] /* steps */
      } /* join_execution */
    }
  ] /* steps */
}
MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0
          INSUFFICIENT_PRIVILEGES: 0
1 row in set (0.00 sec)
  • "filesort_summary" ์„น์…˜์˜ "sort_algorithm" ํ•„๋“œ์— ์ •๋ ฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ํ‘œ์‹œ๋œ๋‹ค.
"filesort_summary": {
  "memory_available": 262144,
  "key_size": 32,
  "row_size": 169,
  "max_rows_per_buffer": 1551,
  "num_rows_estimate": 300252,
  "num_rows_found": 300024,
  "num_initial_chunks_spilled_to_disk": 82,
  "peak_memory_used": 262144,
  "sort_algorithm": "std::stable_sort",
  "sort_mode": "<fixed_sort_key, packed_additional_fields>"
} /* filesort_summary */
  • ๋˜ํ•œ "sort_mode" ํ•„๋“œ์—๋Š” "<fixed_sort_key, packed_additional_fields>"๊ฐ€ ํ‘œ์‹œ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ •ํ™•ํžˆ๋Š” MySQL ์„œ๋ฒ„์˜ ์ •๋ ฌ ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด 3๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.
    1. <sort_key, rowid>: ์ •๋ ฌ ํ‚ค์™€ ๋ ˆ์ฝ”๋“œ์˜ ๋กœ์šฐ ์•„์ด๋””(Row ID)๋งŒ ๊ฐ€์ ธ์™€์„œ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ์‹
    2. <sort_key, additional_fields>: ์ •๋ ฌ ํ‚ค์™€ ๋ ˆ์ฝ”๋“œ ์ „์ฒด๋ฅผ ๊ฐ€์ ธ์™€์„œ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ์‹. ๋ ˆ์ฝ”๋“œ์˜ ์นผ๋Ÿผ๋“ค์€ ๊ณ ์ • ์‚ฌ์ด์ฆˆ๋กœ ๋ฉ”๋ชจ๋ฆฌ ์ €์žฅ
    3. <sort_key, packed_additional_fields>: ์ •๋ ฌ ํ‚ค์™€ ๋ ˆ์ฝ”๋“œ ์ „์ฒด๋ฅผ ๊ฐ€์ ธ์™€์„œ ์ •๋ ฌํ•˜๋Š” ๋ฐฉ์‹. ๋ ˆ์ฝ”๋“œ์˜ ์นผ๋Ÿผ๋“ค์€ ๊ฐ€๋ณ€ ์‚ฌ์ด์ฆˆ๋กœ ๋ฉ”๋ชจ๋ฆฌ ์ €์žฅ
  • ์—ฌ๊ธฐ์„œ ์ฒซ ๋ฒˆ์งธ ๋ฐฉ์‹์„ "ํˆฌ ํŒจ์Šค" ์ •๋ ฌ ๋ฐฉ์‹, ๋‘ ๋ฒˆ์งธ์™€ ์„ธ ๋ฒˆ์งธ ๋ฐฉ์‹์„ "์‹ฑ๊ธ€ ํŒจ์Šค" ์ •๋ ฌ ๋ฐฉ์‹์ด๋ผ ํ•œ๋‹ค.
2-3-2-1. ์‹ฑ๊ธ€ ํŒจ์Šค ์ •๋ ฌ ๋ฐฉ์‹
  • ์†ŒํŠธ ๋ฒ„ํผ์— ์ •๋ ฌ ๊ธฐ์ค€ ์นผ๋Ÿผ์„ ํฌํ•จํ•ด SELECT ๋Œ€์ƒ์ด ๋˜๋Š” ์นผ๋Ÿผ ์ „๋ถ€๋ฅผ ๋‹ด์•„์„œ ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ •๋ ฌ ๋ฐฉ๋ฒ•์ด๋‹ค.
mysql> SELECT emp_no, first_name, last_name
       FROM employees
       ORDER BY first_name;

  • ํ…Œ์ด๋ธ”์„ ์ฝ์„ ๋•Œ '์ •๋ ฌ์— ํ•„์š”ํ•˜์ง€ ์•Š์€ ์นผ๋Ÿผ๊นŒ์ง€ ์ „๋ถ€' ์ฝ์–ด์„œ ์†ŒํŠธ ๋ฒ„ํผ์— ๋‹ด๊ณ  ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • ์ •๋ ฌ์ด ์™„๋ฃŒ๋˜๋ฉด ์ •๋ ฌ ๋ฒ„ํผ์˜ ๋‚ด์šฉ์„ ๊ทธ๋Œ€๋กœ ํด๋ผ์ด์–ธํŠธ๋กœ ๋„˜๊ฒจ์ค€๋‹ค.
2-3-2-2. ํˆฌ ํŒจ์Šค ์ •๋ ฌ ๋ฐฉ์‹
  • ์ •๋ ฌ ๋Œ€์ƒ ์ปฌ๋Ÿผ๊ณผ ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค ๊ฐ’๋งŒ ์†ŒํŠธ ๋ฒ„ํผ์— ๋‹ด์•„์„œ ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ์ •๋ ฌ๋œ ์ˆœ์„œ๋Œ€๋กœ ๋‹ค์‹œ ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค๋กœ ํ…Œ์ด๋ธ”์„ ์ฝ์–ด์˜ค๋Š” ๋ฐฉ์‹
    • ์‹ฑ๊ธ€ ํŒจ์Šค ์ •๋ ฌ ๋ฐฉ์‹์ด ๋„์ž…๋˜๊ธฐ ์ด์ „๋ถ€ํ„ฐ ์‚ฌ์šฉํ•˜๋˜ ๋ฐฉ์‹. ํ•˜์ง€๋งŒ MySQL 8.0์—์„œ๋„ ์—ฌ์ „ํžˆ ํŠน์ • ์กฐ๊ฑด์—์„œ๋Š” ํˆฌ ํŒจ์Šค ์ •๋ ฌ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

  • ์ •๋ ฌ์— ํ•„์š”ํ•œ ์นผ๋Ÿผ + ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค๋งŒ ์ฝ์–ด์„œ ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๋‚˜๋จธ์ง€ ์กฐํšŒ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์ด๋‹ค.
  • ํ…Œ์ด๋ธ”์„ 2๋ฒˆ ์ฝ์–ด์•ผ ํ•œ๋‹ค๋Š” ์ ์—์„œ ๋น„ํšจ์œจ์ ์ด๋‹ค.
    • ์ƒˆ๋กœ์šด ์ •๋ ฌ ๋ฐฉ์‹์ธ ์‹ฑ๊ธ€ ํŒจ์Šค๋Š” ์ด๋Ÿฐ ๋ถˆํ•ฉ๋ฆฌ๊ฐ€ ์—†๋‹ค.
  • ์ตœ์‹  ๋ฒ„์ „์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์‹ฑ๊ธ€ ํŒจ์Šค ์ •๋ ฌ ๋ฐฉ์‹์„ ์ฃผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ๋Œ€์‹  ์‹ฑ๊ธ€ ํŒจ์Šค ๋ฐฉ์‹์€ ๋” ๋งŽ์€ ์†ŒํŠธ ๋ฒ„ํผ์˜ ๊ณต๊ฐ„์ด ํ•„์š”ํ•˜๋‹ค.
    • ex) 128KB ์ •๋ ฌ ๋ฒ„ํผ. ํˆฌ ํŒจ์Šค๋Š” 7,000๊ฑด ๋ ˆ์ฝ”๋“œ ์ •๋ ฌ ๊ฐ€๋Šฅ, ๋ฐ˜๋ฉด ์‹ฑ๊ธ€ ํŒจ์Šค๋Š” ์ ˆ๋ฐ˜์ธ 3,500๊ฑด ์ •๋„๋ฐ–์— ์ •๋ ฌํ•  ์ˆ˜ ์—†๋‹ค.
  • ํ•˜์ง€๋งŒ, ์•„๋ž˜์˜ ๊ฒฝ์šฐ MySQL์€ ์‹ฑ๊ธ€ ํŒจ์Šค ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๊ณ  ํˆฌ ํŒจ์Šค ์ •๋ ฌ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.
    • ๋ ˆ์ฝ”๋“œ์˜ ํฌ๊ธฐ๊ฐ€ max_length_for_sort_data ์‹œ์Šคํ…œ ๋ณ€์ˆ˜์— ์„ค์ •๋œ ๊ฐ’๋ณด๋‹ค ํด ๋•Œ
    • BLOB์ด๋‚˜ TEXT ํƒ€์ž…์˜ ์นผ๋Ÿผ์ด SELECT ๋Œ€์ƒ์— ํฌํ•จ๋  ๋•Œ
  • ์‹ฑ๊ธ€ ํŒจ์Šค๋Š” ๋ ˆ์ฝ”๋“œ์˜ ํฌ๊ธฐ๋‚˜ ๊ฑด์ˆ˜๊ฐ€ ์ž‘์€ ๊ฒฝ์šฐ ๋น ๋ฅธ ๋ฐ˜๋ฉด, ํˆฌ ํŒจ์Šค ๋ฐฉ์‹์€ ๋ ˆ์ฝ”๋“œ์˜ ํฌ๊ธฐ๋‚˜ ๊ฑด์ˆ˜๊ฐ€ ์ƒ๋‹นํžˆ ๋งŽ์€ ๊ฒฝ์šฐ ํšจ์œจ์ ์ด๋‹ค.

์ฃผ์˜

  • SELECT ์ฟผ๋ฆฌ์—์„œ ๊ผญ ํ•„์š”ํ•œ ์นผ๋Ÿผ๋งŒ ์กฐํšŒํ•˜์ง€ ์•Š๊ณ , ๋ชจ๋“  ์นผ๋Ÿผ(*)์„ ๊ฐ€์ ธ์˜ค๋„๋ก ๊ฐœ๋ฐœํ•  ๋•Œ๊ฐ€ ๋งŽ์„ ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Š” ์ •๋ ฌ ๋ฒ„ํผ๋ฅผ ๋ช‡ ๋ฐฐ์—์„œ ๋ช‡์‹ญ ๋ฐฐ๊นŒ์ง€ ๋น„ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ๊ฐ€๋Šฅ์„ฑ์ด ํฌ๋‹ค.
  • SELECT ์ฟผ๋ฆฌ์—์„œ ๊ผญ ํ•„์š”ํ•œ ์นผ๋Ÿผ๋งŒ ์กฐํšŒํ•˜๋„๋ก ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ๊ถŒ์žฅํ•˜๋Š” ๊ฒƒ์€ ๋ฐ”๋กœ ์ด๋Ÿฐ ์ด์œ  ๋•Œ๋ฌธ์ด๋‹ค.

2-3-3. ์ •๋ ฌ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•

  • ORDER BY๊ฐ€ ์‚ฌ์šฉ๋˜๋ฉด ๋ฐ˜๋“œ์‹œ ์•„๋ž˜ 3๊ฐ€์ง€ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋กœ ์ •๋ ฌ์ด ์ฒ˜๋ฆฌ๋œ๋‹ค.
์ •๋ ฌ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ• ์‹คํ–‰ ๊ณ„ํš์˜ Extra ์นผ๋Ÿผ ๋‚ด์šฉ
์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•œ ์ •๋ ฌ ๋ณ„๋„ ํ‘œ๊ธฐ ์—†์Œ
์กฐ์ธ์—์„œ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”๋งŒ ์ •๋ ฌ "Using filesort" ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ๋จ
์กฐ์ธ์—์„œ ์กฐ์ธ ๊ฒฐ๊ณผ๋ฅผ ์ž„์‹œ ํ…Œ์ด๋ธ”๋กœ ์ €์žฅ ํ›„ ์ •๋ ฌ "Using temporary; Using filesort" ๋ฉ”์‹œ์ง€ ํ‘œ์‹œ๋จ
  • ๋จผ์ € ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ์ •๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ฒ€ํ† ํ•œ๋‹ค. ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฒ€์ƒ‰์— ์ •๋ ฌ ๋ฒ„ํผ์— ์ €์žฅํ•˜๋ฉด์„œ ์ •๋ ฌ ์ฒ˜๋ฆฌ(Filesort)๋ฅผ ํ•œ๋‹ค.
  • Filesort๋ฅผ ํ•  ๋•Œ ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” 2๊ฐ€์ง€ ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•œ๋‹ค. (๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ์ „์ž๊ฐ€ ๋” ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์ด๋‹ค.)
    1. ์กฐ์ธ์ด ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”๋งŒ ์ •๋ ฌํ•œ ๋‹ค์Œ ์กฐ์ธ์„ ์ˆ˜ํ–‰
    2. ์กฐ์ธ์ด ๋๋‚˜๊ณ  ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์˜จ ํ›„ ์ •๋ ฌ์„ ์ˆ˜ํ–‰
2-3-3-1. ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•œ ์ •๋ ฌ
  • ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•œ ์ •๋ ฌ์„ ์œ„ํ•ด์„œ๋Š” ๋ฐ˜๋“œ์‹œ ORDER BY์— ๋ฉด์‹œ๋œ ์นผ๋Ÿผ์ด ์ œ์ผ ๋จผ์ € ์ฝ๋Š” ํ…Œ์ด๋ธ”์— ์†ํ•˜๊ณ , ORDER BY์˜ ์ˆœ์„œ๋Œ€๋กœ ์ƒ์„ฑ๋œ ์ธ๋ฑ์Šค๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
    • ๋˜ํ•œ WHERE ์ ˆ์— ์ฒซ ๋ฒˆ์งธ๋กœ ์ฝ๋Š” ํ…Œ์ด๋ธ”์˜ ์นผ๋Ÿผ์— ๋Œ€ํ•œ ์กฐ๊ฑด์ด ์žˆ๋‹ค๋ฉด ๊ทธ ์กฐ๊ฑด๊ณผ ORDER BY๋Š” ๊ฐ™์€ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
    • ๊ทธ๋ฆฌ๊ณ  B-Tree ๊ณ„์—ด์˜ ์ธ๋ฑ์Šค๊ฐ€ ์•„๋‹Œ ํ•ด์‹œ ์ธ๋ฑ์Šค๋‚˜ ์ „๋ฌธ ๊ฒ€์ƒ‰ ์ธ๋ฑ์Šค ๋“ฑ์—์„œ๋Š” ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•œ ์ •๋ ฌ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.
    • ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์ด ์กฐ์ธ๋˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋„ค์Šคํ‹ฐ๋“œ ๋ฃจํ”„ Nested-loop ๋ฐฉ์‹์˜ ์กฐ์ธ์—์„œ๋งŒ ์ด ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•ด ์ •๋ ฌ์ด ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์‹ค์ œ ์ธ๋ฑ์Šค์˜ ๊ฐ’์ด ์ •๋ ฌ๋ผ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ธ๋ฑ์Šค์˜ ์ˆœ์„œ๋Œ€๋กœ ์ฝ๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.
2-3-3-2. ์กฐ์ธ์˜ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”๋งŒ ์ •๋ ฌ
  • ์กฐ์ธ์ด ์ˆ˜ํ–‰๋˜๋ฉด ๋ ˆ์ฝ”๋“œ์˜ ๊ฑด์ˆ˜๊ฐ€ ๋ช‡ ๋ฐฐ๋กœ ๋ถˆ์–ด๋‚˜๊ณ , ๋ ˆ์ฝ”๋“œ ํ•˜๋‚˜ํ•˜๋‚˜์˜ ํฌ๊ธฐ๋„ ๋Š˜์–ด๋‚œ๋‹ค.
    • ๋”ฐ๋ผ์„œ ์กฐ์ธ์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— ์ฒซ ๋ฒˆ์งธ ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋จผ์ € ์ •๋ ฌํ•œ ๋‹ค์Œ ์กฐ์ธ์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ •๋ ฌ์˜ ์ฐจ์„ ์ฑ…์ด ๋  ๊ฒƒ์ด๋‹ค.
    • ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ์ •๋ ฌ์ด ์ฒ˜๋ฆฌ๋˜๋ ค๋ฉด ์กฐ์ธ์—์„œ ์ฒซ ๋ฒˆ์งธ๋กœ ์ฝํžˆ๋Š” ํ…Œ์ด๋ธ”(๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”)์˜ ์นผ๋Ÿผ๋งŒ์œผ๋กœ ORDER BY ์ ˆ์„ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

2-3-3-3. ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์ด์šฉํ•œ ์ •๋ ฌ
  • 2๊ฐœ ์ด์ƒ์˜ ํ…Œ์ด๋ธ”์„ ์กฐ์ธํ•ด์„œ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ •๋ ฌํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์˜ˆ์™ธ! ์กฐ์ธ์˜ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”๋งŒ ์ •๋ ฌํ•  ๋•Œ๋Š” 2๊ฐœ ์ด์ƒ์˜ ํ…Œ์ด๋ธ”์ด ์กฐ์ธ๋˜๋ฉด์„œ ์ •๋ ฌ์ด ์‹คํ–‰๋˜์ง€๋งŒ ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. (์กฐ์ธ๋˜๋Š” ํ…Œ์ด๋ธ”์ด ์ •๋ ฌ ๊ธฐ์ค€์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์—!)
  • ์กฐ์ธ์˜ ๊ฒฐ๊ณผ๋ฅผ ์ž„์‹œ ํ…Œ์ด๋ธ”์— ์ €์žฅํ•˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ์ •๋ ฌํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ์ •๋ ฌ์˜ 3๊ฐ€์ง€ ๋ฐฉ๋ฒ• ๊ฐ€์šด๋ฐ ์ •๋ ฌํ•ด์•ผ ํ•  ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๊ฐ€ ๊ฐ€์žฅ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€์žฅ ๋А๋ฆฐ ์ •๋ ฌ ๋ฐฉ๋ฒ•์ด๋‹ค.
  • ์•„๋ž˜์™€ ๊ฐ™์ด ์ •๋ ฌ ๊ธฐ์ค€์ด ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”์ด ์•„๋‹ˆ๋ผ ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”์— ์žˆ๋‹ค๋ฉด ์ด ์ฟผ๋ฆฌ๋Š” ์กฐ์ธ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์ •๋ ฌํ•ด์•ผ ํ•˜๋ฉด, ์ด ๊ฒฝ์šฐ ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ํ™œ์šฉํ•œ๋‹ค.
mysql> SELECT *
       FROM employees e, salaries s
       WHERE s.emp_no=e.emp_no
         AND e.emp_no BETWEEN 100002 AND 100010
       ORDER BY s.salary;
  • ์œ„ ์ฟผ๋ฆฌ์˜ ์‹คํ–‰๊ณ„ํš์„ ์‚ดํŽด๋ณด์ž. Extra ์นผ๋Ÿผ์— Using where; Using temporary; Using filesort๋ผ๋Š” ์ฝ”๋ฉ˜ํŠธ๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.
    • ์ด๋Š” ์กฐ์ธ์˜ ๊ฒฐ๊ณผ๋ฅผ ์ž„์‹œ ํ…Œ์ด๋ธ”์— ์ €์žฅํ•˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ์ •๋ ฌ ์ฒ˜๋ฆฌํ–ˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค.
+----+-------+-------+---------+----------------------------------------------+
| id | table | type  | key     | Extra                                        |
+----+-------+-------+---------+----------------------------------------------+
|  1 | e     | range | PRIMARY | Using where; Using temporary; Using filesort |
|  1 | s     | ref   | PRIMARY | NULL                                         |
+----+-------+-------+---------+----------------------------------------------+

2-3-3-4. ์ •๋ ฌ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•์˜ ์„ฑ๋Šฅ ๋น„๊ต
  • ์›น ์„œ๋น„์Šค์šฉ ์ฟผ๋ฆฌ์—์„œ๋Š” ORDER BY์™€ ํ•จ๊ป˜ LIMIT์ด ๊ฑฐ์˜ ํ•„์ˆ˜๋กœ ์‚ฌ์šฉ๋œ๋‹ค.
    • LIMIT์€ ํ…Œ์ด๋ธ”์ด๋‚˜ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ์˜ ์ผ๋ถ€๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ ๋•Œ๋ฌธ์— MySQL ์„œ๋ฒ„๊ฐ€ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ์ž‘์—…๋Ÿ‰์„ ์ค„์ด๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.
  • ๊ทธ๋Ÿฐ๋ฐ ORDER BY๋‚˜ GROUP BY ๊ฐ™์€ ์ž‘์—…์€ WHERE ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ LIMIT ๊ฑด์ˆ˜๋งŒํผ๋งŒ ๊ฐ€์ ธ์™€์„œ๋Š” ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋‹ค.
    • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์™€ ์ •๋ ฌ์„ ์ˆ˜ํ–‰ํ•˜๊ฑฐ๋‚˜, ๊ทธ๋ฃจํ•‘ ์ž‘์—…์„ ์‹คํ–‰ํ•ด์•ผ๋งŒ ๋น„๋กœ์†Œ LIMIT์œผ๋กœ ๊ฑด์ˆ˜๋ฅผ ์ œํ•œํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์•„๋ฌด๋ฆฌ WHERE ์กฐ๊ฑด์ด ์ธ๋ฑ์Šค๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋„๋ก ํŠœ๋‹ํ•ด๋„ ์ž˜๋ชป๋œ ORDER BY๋‚˜ GROUP BY ๋•Œ๋ฌธ์— ์ฟผ๋ฆฌ๊ฐ€ ๋А๋ ค์ง€๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ž์ฃผ ๋ฐœ์ƒํ•œ๋‹ค.
2-3-3-4-1. ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐฉ์‹
  • ๋ ˆ์ฝ”๋“œ๊ฐ€ ๊ฒ€์ƒ‰๋  ๋•Œ๋งˆ๋‹ค ๋ฐ”๋กœ๋ฐ”๋กœ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†กํ•ด์ฃผ๋Š” ๋ฐฉ์‹
  • ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฐพ๋Š” ์ฆ‰์‹œ ์ „๋‹ฌ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— ๋™์‹œ์— ๋ฐ์ดํ„ฐ์˜ ๊ฐ€๊ณต ์ž‘์—…์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ŠคํŠธ๋ฆฌ๋ฐ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ์ฟผ๋ฆฌ๋Š” ์ฟผ๋ฆฌ๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋ ˆ์ฝ”๋“œ๋ฅผ ์กฐํšŒํ•˜๋А๋ƒ์— ์ƒ๊ด€์—†์ด ๋น ๋ฅธ ์‘๋‹ต ์‹œ๊ฐ„์„ ๋ณด์žฅํ•ด์ค€๋‹ค.
  • ๋˜ํ•œ, LIMIT์ฒ˜๋Ÿผ ๊ฒฐ๊ณผ ๊ฑด์ˆ˜๋ฅผ ์ œํ•œํ•˜๋Š” ์กฐ๊ฑด๋“ค์€ ์ฟผ๋ฆฌ์˜ ์ „์ฒด ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ƒ๋‹นํžˆ ์ค„์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์žฅ์ ์ด ์žˆ๋‹ค.
2-3-3-4-2. ๋ฒ„ํผ๋ง ๋ฐฉ์‹
  • ORDER BY๋‚˜ GROUP BY ๊ฐ™์€ ์ฒ˜๋ฆฌ๋Š” ์ฟผ๋ฆฌ์˜ ๊ฒฐ๊ณผ๊ฐ€ ์ŠคํŠธ๋ฆฌ๋ฐ๋˜๋Š” ๊ฒƒ์„ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค.
    • WHERE ์กฐ๊ฑด์— ์ผ์น˜ํ•˜๋Š” ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„, ์ •๋ ฌํ•˜๊ฑฐ๋‚˜ ๊ทธ๋ฃจํ•‘ํ•ด์„œ ์ฐจ๋ก€๋Œ€๋กœ ๋ณด๋‚ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
    • MySQL ์„œ๋ฒ„์—์„œ๋Š” ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์ •๋ ฌ ์ž‘์—…์„ ํ•˜๋Š” ๋™์•ˆ ํด๋ผ์ด์–ธํŠธ๋Š” ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๊ณ  ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‘๋‹ต ์†๋„๊ฐ€ ๋А๋ ค์ง„๋‹ค.
  • ๋ฒ„ํผ๋ง ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ์ฟผ๋ฆฌ๋Š” ๋จผ์ € ๊ฒฐ๊ณผ๋ฅผ ๋ชจ์•„์„œ MySQL ์„œ๋ฒ„์—์„œ ์ผ๊ด„ ๊ฐ€๊ณตํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋ชจ๋“  ๊ฒฐ๊ณผ๋ฅผ ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์œผ๋กœ๋ถ€ํ„ฐ ๊ฐ€์ ธ์˜ฌ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค.
    • ๋”ฐ๋ผ์„œ LIMIT์ฒ˜๋Ÿผ ๊ฒฐ๊ณผ ๊ฑด์ˆ˜๋ฅผ ์ œํ•œํ•˜๋Š” ์กฐ๊ฑด์ด ์žˆ์–ด๋„ ์„ฑ๋Šฅ ํ–ฅ์ƒ์— ๋ณ„๋กœ ๋„์›€์ด ๋˜์ง€ ์•Š๋Š”๋‹ค.
    • ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๋Š” ์ค„์ผ ์ˆ˜ ์žˆ์ง€๋งŒ MySQL ์„œ๋ฒ„๊ฐ€ ํ•ด์•ผํ•˜๋Š” ์ž‘์—…๋Ÿ‰์—๋Š” ๊ทธ๋‹ค์ง€ ๋ณ€ํ™”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
์ •๋ ฌ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ• ์ •๋ฆฌ
  • ORDER BY์˜ 3๊ฐ€์ง€ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ• ์ค‘ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•œ ์ •๋ ฌ ๋ฐฉ์‹๋งŒ ์ŠคํŠธ๋ฆฌ๋ฐ ํ˜•ํƒœ์˜ ์ฒ˜๋ฆฌ์ด๋‹ค.
  • "์กฐ์ธ์—์„œ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”๋งŒ ์ •๋ ฌ"๊ณผ "์กฐ์ธ์—์„œ ์กฐ์ธ ๊ฒฐ๊ณผ๋ฅผ ์ž„์‹œ ํ…Œ์ด๋ธ”๋กœ ์ €์žฅ ํ›„ ์ •๋ ฌ"์€ ๋ชจ๋‘ ๋ฒ„ํผ๋ง๋œ ํ›„์— ์ •๋ ฌ๋œ๋‹ค.
  • ์ฆ‰ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•œ ๋ฐฉ์‹์€ LIMIT์œผ๋กœ ์ œํ•œ๋œ ๊ฑด์ˆ˜๋งŒํผ๋งŒ ์ฝ์œผ๋ฉด ๋ฐ”๋กœ๋ฐ”๋กœ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†กํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ง์ด๋‹ค.
์ •๋ ฌ ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ• ์˜ˆ์‹œ
  • ์˜ˆ์‹œ ๊ฐ€์ •
  1. tb1์˜ ๋ ˆ์ฝ”๋“œ๊ฐ€ 100๊ฑด
  2. tb2 ๋ ˆ์ฝ”๋“œ๊ฐ€ 1,000๊ฑด
  3. tb1 ํ…Œ์ด๋ธ” 1๊ฑด๋‹น, tb2 ํ…Œ์ด๋ธ” 10๊ฑด์ด ์žˆ์Œ์„ ๊ฐ€์ •
  4. ๋‘ ํ…Œ์ด๋ธ” ์กฐ์ธ ๊ฒฐ๊ณผ๋Š” ์ „์ฒด 1,000๊ฑด์ด๋ผ๊ณ  ๊ฐ€์ •ํ•œ ์˜ˆ์‹œ
  • ๋จผ์ € tb1์ด ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”์ด๋ผ๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ
์ •๋ ฌ ๋ฐฉ๋ฒ• ์ฝ์–ด์•ผ ํ•  ๊ฑด์ˆ˜ ์กฐ์ธ ํšŸ์ˆ˜ ์ •๋ ฌํ•ด์•ผ ํ•  ๋Œ€์ƒ ๊ฑด์ˆ˜
์ธ๋ฑ์Šค ์‚ฌ์šฉ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”: 1๊ฑด
๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”: 10๊ฑด
1๋ฒˆ 0๊ฑด
์กฐ์ธ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”๋งŒ ์ •๋ ฌ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”: 100๊ฑด
๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”: 10๊ฑด
1๋ฒˆ 100๊ฑด(๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ” ๊ฑด์ˆ˜๋งŒํผ ์ •๋ ฌ ํ•„์š”)
์ž„์‹œ ํ…Œ์ด๋ธ” ์‚ฌ์šฉ ํ›„ ์ •๋ ฌ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”: 100๊ฑด
๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”: 1,000๊ฑด
100๋ฒˆ(๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ” ๊ฑด์ˆ˜๋งŒํผ ์กฐ์ธ ๋ฐœ์ƒ) 1,000๊ฑด(์กฐ์ธ๋œ ๊ฒฐ๊ณผ ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๋ฅผ ์ „๋ถ€ ์ •๋ ฌํ•ด์•ผ ํ•จ)
  • tb2๊ฐ€ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”์ด๋ผ๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ
์ •๋ ฌ ๋ฐฉ๋ฒ• ์ฝ์–ด์•ผ ํ•  ๊ฑด์ˆ˜ ์กฐ์ธ ํšŸ์ˆ˜ ์ •๋ ฌํ•ด์•ผ ํ•  ๋Œ€์ƒ ๊ฑด์ˆ˜
์ธ๋ฑ์Šค ์‚ฌ์šฉ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”: 10๊ฑด
๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”: 10๊ฑด
10๋ฒˆ 0๊ฑด
์กฐ์ธ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”๋งŒ ์ •๋ ฌ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”: 1000๊ฑด
๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”: 10๊ฑด
100๋ฒˆ 1,000๊ฑด(๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ” ๊ฑด์ˆ˜๋งŒํผ ์ •๋ ฌ ํ•„์š”)
์ž„์‹œ ํ…Œ์ด๋ธ” ์‚ฌ์šฉ ํ›„ ์ •๋ ฌ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”: 1,000๊ฑด
๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”: 100๊ฑด
1,000๋ฒˆ(๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ” ๊ฑด์ˆ˜๋งŒํผ ์กฐ์ธ ๋ฐœ์ƒ) 1,000๊ฑด(์กฐ์ธ๋œ ๊ฒฐ๊ณผ ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๋ฅผ ์ „๋ถ€ ์ •๋ ฌํ•ด์•ผ ํ•จ)
  • ์–ด๋А ํ…Œ์ด๋ธ”์ด ๋จผ์ € ๋“œ๋ผ์ด๋น™๋˜์–ด ์กฐ์ธ๋˜๋Š”์ง€๋„ ์ค‘์š”ํ•˜์ง€๋งŒ ์–ด๋–ค ์ •๋ ฌ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š”์ง€๋Š” ๋” ํฐ ์„ฑ๋Šฅ ์ฐจ์ด๋ฅผ ๋งŒ๋“ ๋‹ค.
  • ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•œ ์ •๋ ฌ๋กœ ์œ ๋„ํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ๋ชปํ•˜๋‹ค๋ฉด ์ตœ์†Œํ•œ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”๋งŒ ์ •๋ ฌํ•ด๋„ ๋˜๋Š” ์ˆ˜์ค€์œผ๋กœ ์œ ๋„ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ํŠœ๋‹ ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฐ‘์ž๊ธฐ ๊ถ๊ธˆํ•ด์„œ ์ฐพ์•„๋ณธ ์ •๋ณด!

์š”์ฆ˜ date๋‚˜ datetime ํƒ€์ž…์˜ ์ปฌ๋Ÿผ์œผ๋กœ ์ •๋ ฌํ•  ์ผ์ด ๋งŽ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ DATE_FORMAT์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ?!? MySQL์—์„œ๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ธ๋ฑ์Šค๊ฐ€ ํƒ€์งˆ๊นŒ?

์ •๋‹ต์€ "์ธ๋ฑ์Šค๋ฅผ ํƒ€์ง€ ์•Š๋Š”๋‹ค"์ด๋‹ค. MySQL์—์„œ๋Š” ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ธ๋ฑ์Šค๋ฅผ ํƒ€์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•œ๋‹ค. ์‹ ๊ธฐํ–ˆ๋˜ ์ ์€ BETWEEN๊ณผ ๊ฐ™์€ ํ•จ์ˆ˜ ๋˜ํ•œ ์ธ๋ฑ์Šค๋ฅผ ํƒ€์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด๋‹ค! ๋•Œ๋ฌธ์— ์ž์ œํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ๋‚ ์งœ๋ฅผ ๊ฒ€์ƒ‰ํ•  ๋•Œ ์•„๋ž˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด ๊ฒ€์ƒ‰ํ•˜์ž.

SELECT *
FROM order
where order_date >= '2023-11-21'
and order_date < '2023-11-22'
SELECT *
FROM order
where order_date >= '2023-11-21 00:00:00'
and order_date < '2023-11-22 23:59:59'

2-3-4. ์ •๋ ฌ ๊ด€๋ จ ์ƒํƒœ ๋ณ€์ˆ˜

  • MySQL ์„œ๋ฒ„๋Š” ์ฒ˜๋ฆฌํ•˜๋Š” ์ฃผ์š” ์ž‘์—…์— ๋Œ€ํ•ด์„œ๋Š” ํ•ด๋‹น ์ž‘์—…์˜ ์‹คํ–‰ ํšŸ์ˆ˜๋ฅผ ์ƒํƒœ ๋ณ€์ˆ˜๋กœ ์ €์žฅํ•œ๋‹ค.
  • ์ง€๊ธˆ๊นŒ์ง€ ๋ช‡ ๊ฑด์˜ ๋ ˆ์ฝ”๋“œ๋‚˜ ์ •๋ ฌ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ–ˆ๋Š”์ง€, ์†ŒํŠธ ๋ฒ„ํผ ๊ฐ„์˜ ๋ณ‘ํ•ฉ ์ž‘์—…์€ ๋ช‡ ๋ฒˆ์ด๋‚˜ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ๋“ฑ์„ ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
mysql> FLUSH STATUS;
mysql> SHOW STATUS LIKE 'Sort%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Sort_merge_passes | 0     |
| Sort_range        | 0     |
| Sort_rows         | 0     |
| Sort_scan         | 0     |
+-------------------+-------+
  • Sort_merge_passes๋Š” ๋ฉ€ํ‹ฐ ๋จธ์ง€ ์ฒ˜๋ฆฌ ํšŸ์ˆ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  • Sort_range๋Š” ์ธ๋ฑ์Šค ๋ ˆ์ธ์ง€ ์Šค์บ”์„ ํ†ตํ•ด ๊ฒ€์ƒ‰๋œ ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ ์ •๋ ฌ ์ž‘์—… ํšŸ์ˆ˜๋‹ค.
  • Sort_rows๋Š” ์ง€๊ธˆ๊นŒ์ง€ ์ •๋ ฌํ•œ ์ „์ฒด ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
  • Sort_scan์€ ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์„ ํ†ตํ•ด ๊ฒ€์ƒ‰๋œ ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ ์ •๋ ฌ ์ž‘์—… ํšŸ์ˆ˜๋‹ค.

2-4. GROUP BY ์ฒ˜๋ฆฌ

  • GROUP BY ๋˜ํ•œ ORDER BY์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ฟผ๋ฆฌ๊ฐ€ ์ŠคํŠธ๋ฆฌ๋ฐ๋œ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์—†๊ฒŒ ํ•˜๋Š” ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜๋‹ค.
  • GROUP BY์—์„œ๋Š” HAVING ์ ˆ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ฒฐ๊ณผ์— ๋Œ€ํ•ด ํ•„ํ„ฐ๋ง ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • GROUP BY์—์„œ ์‚ฌ์šฉ๋œ ์กฐ๊ฑด์€ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ HAVING ์ ˆ์„ ํŠœ๋‹ํ•˜๋ ค๊ณ  ํ•˜๋Š” ์–ด๋ฆฌ์„์Œ์€ ๋ฒ”ํ•˜์ง€ ๋ง์ž.
  • GROUP BY๋„ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์™€ ๊ทธ๋ ‡์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋‹ค.
  • ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ
    • ์ธ๋ฑ์Šค๋ฅผ ์ฐจ๋ก€๋Œ€๋กœ ์ฝ๋Š” ์ธ๋ฑ์Šค ์Šค์บ” ๋ฐฉ๋ฒ•
    • ์ธ๋ฑ์Šค๋ฅผ ๊ฑด๋„ˆ๋›ฐ๋ฉด์„œ ์ฝ๋Š” ๋ฃจ์Šค ์ธ๋ฑ์Šค ์Šค์บ” ๋ฐฉ๋ฒ•
  • ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ
    • ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•œ๋‹ค.

2-4-1. ์ธ๋ฑ์Šค ์Šค์บ”์„ ์ด์šฉํ•˜๋Š” GROUP BY(ํƒ€์ดํŠธ ์ธ๋ฑ์Šค ์Šค์บ”)

  • ์กฐ์ธ์˜ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”์— ์†ํ•œ ์ปฌ๋Ÿผ๋งŒ ์ด์šฉํ•ด ๊ทธ๋ฃจํ•‘ํ•  ๋•Œ GROUP BY ์นผ๋Ÿผ์œผ๋กœ ์ด๋ฏธ ์ธ๋ฑ์Šค๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ทธ ์ธ๋ฑ์Šค๋ฅผ ์ฐจ๋ก€๋Œ€๋กœ ์ฝ์œผ๋ฉด์„œ ๊ทธ๋ฃจํ•‘ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋กœ ์กฐ์ธ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  • GROUP BY๊ฐ€ ์ธ๋ฑ์Šค๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค ํ•˜๋”๋ผ๋„ ๊ทธ๋ฃน ํ•ฉ์ˆ˜(Aggregation Function) ๋“ฑ์˜ ๊ทธ๋ฃน๊ฐ’์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ด์„œ ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ํ•„์š”ํ•  ๋•Œ๋„ ์žˆ๋‹ค.
  • ์ด๋Ÿฌํ•œ ๊ทธ๋ฃจํ•‘ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ์ฟผ๋ฆฌ์˜ ์‹คํ–‰ ๊ณ„ํš์—์„œ๋Š” Extra ์นผ๋Ÿผ์— ๋ณ„๋„๋กœ GROUP BY ์ฝ”๋ฉ˜ํŠธ "Using index for group-by"๋‚˜ ์ž„์‹œ ํ…Œ์ด๋ธ” ์‚ฌ์šฉ ๋˜๋Š” ์ •๋ ฌ ๊ด€๋ จ ์ฝ”๋ฉ˜ํŠธ "Using temporary, Using filesort"๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค.

๋ฃจ์Šค ์ธ๋ฑ์Šค ์Šค์บ”์„ ์ด์šฉํ•˜๋Š” GROUP BY

  • ์ธ๋ฑ์Šค์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฑด๋„ˆ๋›ฐ๋ฉด์„œ ํ•„์š”ํ•œ ๋ถ€๋ถ€๋งŒ ์ฝ์–ด์„œ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
  • ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ๋ฃจ์Šค ์ธ๋ฑ์Šค ์Šค์บ”์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์‹คํ–‰ ๊ณ„ํš์˜ Extra ์นผ๋Ÿผ์— "Using index for group-by" ์ฝ”๋ฉ˜ํŠธ๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.
  • ์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ณด์ž. ์•„๋ž˜ ํ…Œ์ด๋ธ”์€ (emp_no, from_date)์˜ ๊ทธ๋ฃน ํ‚ค๋ฅผ primary key๋กœ ๊ฐ€์ง€๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค.
mysql> desc salaries;
+-----------+------+------+-----+---------+-------+
| Field     | Type | Null | Key | Default | Extra |
+-----------+------+------+-----+---------+-------+
| emp_no    | int  | NO   | PRI | NULL    |       |
| salary    | int  | NO   | MUL | NULL    |       |
| from_date | date | NO   | PRI | NULL    |       |
| to_date   | date | NO   |     | NULL    |       |
+-----------+------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> EXPLAIN
    -> SELECT emp_no
    -> FROM salaries
    -> WHERE from_date='1985-03-01'
    -> GROUP BY emp_no;
+----+----------+-------+---------+--------+----------+---------------------------------------+
| id | table    | type  | key     | rows   | filtered | Extra                                 |
+----+----------+-------+---------+--------+----------+---------------------------------------+
|  1 | salaries | range | PRIMARY | 299646 |   100.00 | Using where; Using index for group-by |
+----+----------+-------+---------+--------+----------+---------------------------------------+
1 row in set, 1 warning (0.00 sec)
  • ์œ„ ์ฟผ๋ฆฌ๋Š” ์•„๋ž˜์˜ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰๋œ๋‹ค.
  1. (emp_no, from_date) ์ธ๋ฑ์Šค๋ฅผ ์ฐจ๋ก€๋Œ€๋กœ ์Šค์บ”ํ•˜๋ฉด emp_no์˜ ์ฒซ ๋ฒˆ์งธ ์œ ์ผํ•œ ๊ฐ’(๊ทธ๋ฃน ํ‚ค) '10001'์„ ์ฐพ์•„๋‚ธ๋‹ค.
  2. (emp_no, from_date) ์ธ๋ฑ์Šค์—์„œ emp_no๊ฐ€ '10001'์ธ ๊ฒƒ ์ค‘์—์„œ from_date ๊ฐ’์ด '1985-03-01'์ธ ๋ ˆ์ฝ”๋“œ๋งŒ ๊ฐ€์ ธ์˜จ๋‹ค.
    • '10001' ๊ฐ’๊ณผ WHERE ์ ˆ์— ์‚ฌ์šฉ๋œ from_date='1985-03-01' ์กฐ๊ฑด์„ ํ•ฉ์ณ์„œ emp_no=10001 AND from_date='1985-03-01' ์กฐ๊ฑด์œผ๋กœ (emp_no, from_date) ์ธ๋ฑ์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฑฐ์˜ ํก์‚ฌํ•˜๋‹ค.
  3. (emp_no, from_date) ์ธ๋ฑ์Šค์—์„œ emp_no์˜ ๊ทธ ๋‹ค์Œ ์œ ๋‹ˆํฌํ•œ ๊ฐ’์„ ๊ฐ€์ ธ์˜จ๋‹ค. (๊ทธ๋ฃนํ‚ค)
  4. ๊ฒฐ๊ณผ๊ฐ€ ๋” ์—†์œผ๋ฉด ์ฒ˜๋ฆฌ๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  ๊ฒฐ๊ณผ๊ฐ€ ์žˆ๋‹ค๋ฉด 2๋ฒˆ ๊ณผ์ •์œผ๋กœ ๋Œ์•„๊ฐ€ ๋ฐ˜๋ณต ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • MySQL์˜ ๋ฃจ์Šค ์ธ๋ฑ์Šค ์Šค์บ” ๋ฐฉ์‹์€ ๋‹จ์ผ ํ…Œ์ด๋ธ”์— ๋Œ€ํ•ด ์ˆ˜ํ–‰๋˜๋Š” GROUP BY ์ฒ˜๋ฆฌ์—๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋˜ํ•œ Prefix Index, ์นผ๋Ÿผ์˜ ์•ž์ชฝ ์ผ๋ถ€๋งŒ์œผ๋กœ ์ƒ์„ฑ๋œ ์ธ๋ฑ์Šค๋Š” ๋ฃจ์Šค ์ธ๋ฑ์Šค ์Šค์บ”์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.
  • ์ธ๋ฑ์Šค ๋ ˆ์ธ์ง€ ์Šค์บ”์€ ์œ ๋‹ˆํฌํ•œ ๊ฐ’์˜ ์ˆ˜๊ฐ€ ๋งŽ์„์ˆ˜๋ก ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋˜๋Š” ๋ฐ˜๋ฉด ๋ฃจ์Šค ์ธ๋ฑ์Šค ์Šค์บ”์—์„œ๋Š” ์ธ๋ฑ์Šค์˜ ์œ ๋‹ˆํฌํ•œ ๊ฐ’์˜ ์ˆ˜๊ฐ€ ์ ์„์ˆ˜๋ก ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋œ๋‹ค.
    • ์ฆ‰, ๋ฃจ์Šค ์ธ๋ฑ์Šค ์Šค์บ”์€ ๋ถ„ํฌ๋„๊ฐ€ ์ข‹์ง€ ์•Š์€ ์ธ๋ฑ์Šค์ผ์ˆ˜๋ก ๋” ๋น ๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค์–ด๋‚ธ๋‹ค.
  • ๋ฃจ์Šค ์ธ๋ฑ์Šค ์Šค์บ”์ด ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์„์ง€ ์—†์„์ง€ ํŒ๋‹จํ•˜๋Š” ๊ฒƒ์€ WHERE ์ ˆ์˜ ์กฐ๊ฑด์ด๋‚˜ ORDER BY ์ ˆ์ด ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„์ง€ ์—†์„์ง€ ํŒ๋‹จํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค๋Š” ๋” ์–ด๋ ต๋‹ค.

์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜๋Š” GROUP BY

  • ๊ธฐ์ค€ ์นผ๋Ÿฝ์ด ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”์— ์žˆ๋“  ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”์— ์žˆ๋Š” ๊ด€๊ณ„ ์—†์ด ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค๋ฉด ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • ์‹คํ–‰ ๊ณ„ํš์„ ์‚ดํŽด๋ณด๋ฉด Extra ์นผ๋Ÿผ์— "Using temporary"๋ผ๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.
mysql> EXPLAIN 
    SELECT e.last_name, AVG(s.salary) 
    FROM employees e, salaries s 
    WHERE s.emp_no = e.emp_no 
    GROUP BY e.last_name;
+----+-------+------+---------+--------+-----------------+
| id | table | type | key     | rows   | Extra           |
+----+-------+------+---------+--------+-----------------+
|  1 | e     | ALL  | NULL    | 300252 | Using temporary |
|  1 | s     | ref  | PRIMARY |      9 | NULL            |
+----+-------+------+---------+--------+-----------------+
2 rows in set, 1 warning (0.00 sec)
  • MySQL 8.0 ์ด์ „ ๋ฒ„์ „๊นŒ์ง€๋Š” GROUP BY๊ฐ€ ์‚ฌ์šฉ๋œ ์ฟผ๋ฆฌ๋Š” ๊ทธ๋ฃจํ•‘๋˜๋Š” ์นผ๋Ÿผ์„ ๊ธฐ์ค€์œผ๋กœ ๋ฌต์‹œ์ ์ธ ์ •๋ ฌ๊นŒ์ง€ ์ˆ˜ํ–‰ํ–ˆ๋‹ค.
    • GROUP BY๋งŒ ํ•ด๋„ Extra์— "Using temporary"์™€ "Using filesort"๊ฐ€ ๊ฐ™์ด ์ฐํ˜”๋‹ค๋Š” ์–˜๊ธฐ๋‹ค.
  • ํ•˜์ง€๋งŒ MySQL 8.0์—์„œ๋Š” GROUP BY๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋‚ด๋ถ€์ ์œผ๋กœ GROUP BY ์ ˆ์˜ ์นผ๋Ÿผ๋“ค๋กœ ๊ตฌ์„ฑ๋œ ์œ ๋‹ˆํฌ ์ธ๋ฑ์Šค๋ฅผ ๊ฐ€์ง„ ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด์„œ ์ค‘๋ณต ์ œ๊ฑฐ์™€ ์ง‘ํ•ฉ ํ•จ์ˆ˜ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
    • ๊ทธ๋ฆฌ๊ณ  ์กฐ์ธ์˜ ๊ฒฐ๊ณผ๋ฅผ ํ•œ ๊ฑด์”ฉ ๊ฐ€์ ธ์™€ ์ž„์‹œ ํ…Œ์ด๋ธ”์—์„œ ์ค‘๋ณต ์ฒดํฌ๋ฅผ ํ•˜๋ฉด์„œ INSERT ๋˜๋Š” UPDATE๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.
CREATE TEMPORARY TABLE ... (
    last_name VARCHAR(16),
    salary INT,
    UNIQUE INDEX ux_lastname(last_name)
)
  • GROUP BY์™€ ORDER BY๊ฐ€ ๊ฐ™์ด ์‹คํ–‰๋˜๋ฉด ๋ช…์‹œ์ ์œผ๋กœ ์ •๋ ฌ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ Extra ์นผ๋Ÿผ์— "Using temporary์™€ Using filesort"๊ฐ€ ๊ฐ™์ด ํ‘œ์‹œ๋œ๋‹ค.
mysql> EXPLAIN 
    SELECT e.last_name, AVG(s.salary) 
    FROM employees e, salaries s 
    WHERE s.emp_no = e.emp_no 
    GROUP BY e.last_name 
    ORDER BY e.last_name;
+----+-------+------+---------+--------+---------------------------------+
| id | table | type | key     | rows   | Extra                           |
+----+-------+------+---------+--------+---------------------------------+
|  1 | e     | ALL  | NULL    | 300252 | Using temporary; Using filesort |
|  1 | s     | ref  | PRIMARY |      9 | NULL                            |
+----+-------+------+---------+--------+---------------------------------+
2 rows in set, 1 warning (0.00 sec)

2-5. DISTINCT ์ฒ˜๋ฆฌ

  • ํŠน์ • ์นผ๋Ÿผ์˜ ์œ ๋‹ˆํฌํ•œ ๊ฐ’๋งŒ ์กฐํšŒํ•˜๋ ค๋ฉด SELECT ์ฟผ๋ฆฌ์— DISTINCT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • MIN, MAX, COUNT์™€ ๊ฐ™์€ ์ง‘ํ•ฉ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ์™€ ์ง‘ํ•ฉ ํ•จ์ˆ˜๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ 2๊ฐ€์ง€๋กœ ๊ตฌ๋ถ„ํ•ด์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
    • ๊ฐ ๊ฒฝ์šฐ๋งˆ๋‹ค DISTINCT ํ‚ค์›Œ๋“œ๊ฐ€ ๋ฏธ์น˜๋Š” ๋ฒ”์œ„๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค.
  • ๋˜ํ•œ DISTINCE ์ฒ˜๋ฆฌ๊ฐ€ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•  ๋•Œ ํ•ญ์ƒ ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ํ•„์š”ํ•˜๋‹ค. ํ•˜์ง€๋งŒ ์‹คํ–‰ ๊ณ„ํš์˜ Extra ์นผ๋Ÿผ์—๋Š” "Using temporary" ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜์ง€ ์•Š๋Š”๋‹ค.

2-5-1. SELECT DISTINCT ...

  • ๋‹จ์ˆœํžˆ SELECT๋˜๋Š” ๋ ˆ์ฝ”๋“œ ์ค‘์—์„œ ์œ ๋‹ˆํฌํ•œ ๋ ˆ์ฝ”๋“œ๋งŒ ๊ฐ€์ ธ์˜ค๊ณ ์ž ํ•˜๋ฉด SELECT DISTINCT ํ˜•ํƒœ์˜ ์ฟผ๋ฆฌ ๋ฌธ์žฅ์„ ์‚ฌ์šฉํ•œ๋‹ค.
    • ์ด ๊ฒฝ์šฐ์—๋Š” GROUP BY์™€ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.
  • ํŠนํžˆ MySQL 8.0 ๋ฒ„์ „๋ถ€ํ„ฐ๋Š” GROUP BY๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฟผ๋ฆฌ์— ORDER BY ์ ˆ์ด ์—†์œผ๋ฉด ์ •๋ ฌ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ์˜ ๋‘ ์ฟผ๋ฆฌ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
mysql> SELECT DISTINCT emp_no FROM salaries;
mysql> SELECT emp_no FROM salaries GROUP BY emp_no;
  • ํ•˜๋‚˜ ์ฃผ์˜ํ•  ์ ์ด ์žˆ๋Š”๋ฐ, DISTINCT๋Š” SELECTํ•˜๋Š” ๋ ˆ์ฝ”๋“œ(ํŠœํ”Œ)์„ ์œ ๋‹ˆํฌํ•˜๊ฒŒ SELECTํ•˜๋Š” ๊ฒƒ์ด์ง€, ํŠน์ • ์นผ๋Ÿผ๋งŒ ์œ ๋‹ˆํฌํ•˜๊ฒŒ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.
  • ๊ทธ๋Ÿฐ๋ฐ ์•„๋ž˜์™€ ๊ฐ™์ด DISTINCT๋ฅผ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค.
SELECT DISTINCT(first_name), last_name FROM employees;
  • ๋ฌธ์ œ ์—†์ด ์‹คํ–‰๋˜๋Š” ๊ฒƒ ๊ฐ™์•„ ๋ณด์ด์ง€๋งŒ, MySQL ์„œ๋ฒ„๋Š” DISTINCT ๋’ค์˜ ๊ด„ํ˜ธ๋ฅผ ๊ทธ๋ƒฅ ์˜๋ฏธ ์—†์ด ์‚ฌ์šฉ๋œ ๊ด„ํ˜ธ๋กœ ํ•ด์„ํ•˜๊ณ  ์ œ๊ฑฐํ•ด๋ฒ„๋ฆฐ๋‹ค. DISTINCT๋Š” ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ ๋’ค์˜ ๊ด„ํ˜ธ๋Š” ์˜๋ฏธ๊ฐ€ ์—†๋Š” ๊ฒƒ์ด๋‹ค.
  • ๋”ฐ๋ผ์„œ SELECT ์ ˆ์— ์‚ฌ์šฉ๋œ DISTINCT ํ‚ค์›Œ๋“œ๋Š” ์กฐํšŒ๋˜๋Š” ๋ชจ๋“  ์นผ๋Ÿผ์— ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค.
  • ๋‹จ, ์ด์–ด์„œ ์„ค๋ช…ํ•  ์ง‘ํ•ฉ ํ•จ์ˆ˜์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋œ DISTINCT์˜ ๊ฒฝ์šฐ ์กฐ๊ธˆ ๋‹ค๋ฅด๋‹ค.

2-5-2. ์ง‘ํ•ฉ ํ•จ์ˆ˜์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋œ DISTINCT

  • ์ง‘ํ•ฉ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ผ๋ฐ˜์ ์œผ๋กœ SELECT DISTINCT์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ํ•ด์„๋œ๋‹ค.
  • ์ง‘ํ•ฉ ํ•จ์ˆ˜ ๋‚ด์—์„œ ์‚ฌ์šฉ๋œ DISTINCT๋Š” ๊ทธ ์ง‘ํ•ฉ ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ์ „๋‹ฌ๋œ ์นผ๋Ÿผ๊ฐ’์ด ์œ ๋‹ˆํฌํ•œ ๊ฒƒ๋“ค์„ ๊ฐ€์ ธ์˜จ๋‹ค.
mysql> EXPLAIN 
    SELECT COUNT(DISTINCT s.salary) 
    FROM employees e, salaries s 
    WHERE e.emp_no = s.emp_no 
      AND e.emp_no BETWEEN 100001 AND 100100;
+----+-------+-------+---------+------+--------------------------+
| id | table | type  | key     | rows | Extra                    |
+----+-------+-------+---------+------+--------------------------+
|  1 | e     | range | PRIMARY |  100 | Using where; Using index |
|  1 | s     | ref   | PRIMARY |    9 | NULL                     |
+----+-------+-------+---------+------+--------------------------+
2 rows in set, 1 warning (0.00 sec)
  • ์œ„ ์ฟผ๋ฆฌ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ COUNT(DISTINCT s.salary)๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • ํ•˜์ง€๋งŒ ์‹คํ–‰ ๊ณ„ํš์—๋Š” ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๋ฉ”์‹œ์ง€์ธ "Using temporary"๊ฐ€ ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค.
  • ์ด๋•Œ ์ž„์‹œ ํ…Œ์ด๋ธ”์˜ salary ์นผ๋Ÿผ์—๋Š” ์œ ๋‹ˆํฌ ์ธ๋ฑ์Šค๊ฐ€ ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๊ฐ€ ๋งŽ์•„์ง„๋‹ค๋ฉด ์ƒ๋‹นํžˆ ๋А๋ ค์งˆ ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ์˜ ์ฟผ๋ฆฌ๊ฐ€ ๋œ๋‹ค.

2-6. ๋‚ด๋ถ€ ์ž„์‹œ ํ…Œ์ด๋ธ” ํ™œ์šฉ

  • MySQL ์—”์ง„์ด ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์œผ๋กœ๋ถ€ํ„ฐ ๋ฐ›์•„์˜จ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ •๋ ฌํ•˜๊ฑฐ๋‚˜ ๊ทธ๋ฃจํ•‘ํ•  ๋•Œ๋Š” ๋‚ด๋ถ€ ์ž„์‹œ ํ…Œ์ด๋ธ”(Internal temporary table)์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • ๋‚ด๋ถ€ ์ž„์‹œ ํ…Œ์ด๋ธ”์€ CREATE TEMPORARY TABLE ๋ช…๋ น์œผ๋กœ ๋งŒ๋“  ์ž„์‹œ ํ…Œ์ด๋ธ”๊ณผ๋Š”๋Š” ๋‹ค๋ฅด๋‹ค.
  • ์ผ๋ฐ˜์ ์ธ ์ž„์‹œ ํ…Œ์ด๋ธ”์€ ์ฒ˜์Œ์— ๋ฉ”๋ชจ๋ฆฌ์— ์ƒ์„ฑ๋๋‹ค๊ฐ€ ํ…Œ์ด๋ธ”์˜ ํฌ๊ธฐ๊ฐ€ ์ปค์ง€๋ฉด ๋””์Šคํฌ๋กœ ์˜ฎ๊ฒจ์ง„๋‹ค.
    • ํŠน์ • ์˜ˆ์™ธ ์ผ€์ด์Šค์—๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ๋ฐ”๋กœ ๋””์Šคํฌ์— ๋งŒ๋“ค์–ด์ง€๊ธฐ๋„ ํ•œ๋‹ค.
  • ๋‚ด๋ถ€ ์ž„์‹œ ํ…Œ์ด๋ธ”์€ ๋‚ด๋ถ€์ ์ธ ๊ฐ€๊ณต์„ ์œ„ํ•ด MySQL ์—”์ง„์ด ์ง์ ‘ ์ƒ์„ฑํ•˜๋ฉฐ ๋‹ค๋ฅธ ์„ธ์…˜์ด๋‚˜ ๋‹ค๋ฅธ ์ฟผ๋ฆฌ์—์„œ ๋ณผ ์ˆ˜ ์—†์œผ๋ฉฐ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋„ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
    • ๋˜ํ•œ ์ฟผ๋ฆฌ์˜ ์ฒ˜๋ฆฌ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ์ž๋™์œผ๋กœ ์‚ญ์ œ๋œ๋‹ค๋Š” ์ ์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ์„ฑํ•˜๋Š” ์ž„์‹œ ํ…Œ์ด๋ธ”๊ณผ๋Š” ๋‹ค๋ฅด๋‹ค.

2-6-1. ๋ฉ”๋ชจ๋ฆฌ ์ž„์‹œ ํ…Œ์ด๋ธ”๊ณผ ๋””์Šคํฌ ์ž„์‹œ ํ…Œ์ด๋ธ”

  • MySQL 8.0 ์ด์ „์—๋Š” ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” MEMORY ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์„ ์‚ฌ์šฉํ•˜๊ณ , ๋””์Šคํฌ์— ์ €์žฅ๋  ๋•Œ๋Š” MyISAM ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์„ ์‚ฌ์šฉํ–ˆ๋‹ค.
    • MEMORY ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์€ ๊ฐ€๋ณ€ ๊ธธ์ด ํƒ€์ž…(VARBINARY, VARCHAR)์„ ์ง€์›ํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ๋ฉ”๋ชจ๋ฆฌ์— ๋งŒ๋“ค์–ด์ง€๋ฉด ๊ฐ€๋ณ€ ํƒ€์ž…์˜ ๊ฒจ์šฐ ์ตœ๋Œ€ ๊ธธ์ด ๋งŒํผ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‚ญ๋น„๊ฐ€ ์‹ฌํ–ˆ๋‹ค.
    • ๋˜ํ•œ MyISAM์—์„œ ๋””์Šคํฌ์— ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์—ˆ์„ ๋• ํŠธ๋žœ์žญ์…˜์„ ์ง€์›ํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ๋ฌธ์ œ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ๋‹ค.
  • 8.0 ๋ฒ„์ „๋ถ€ํ„ฐ๋Š” ๋ฉ”๋ชจ๋ฆฌ๋Š” TempTable์ด๋ผ๋Š” ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์„ ์‚ฌ์šฉํ•˜๊ณ , ๋””์Šคํฌ์— ์ €์žฅ๋˜๋Š” ์ž„์‹œ ํ…Œ์ด๋ธ”์€ InnoDB ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์„ ์‚ฌ์šฉํ•˜๋„๋ก ๊ฐœ์„ ํ–ˆ๋‹ค.
    • TempTable์€ ๊ฐ€๋ณ€ ๊ธธ์ด ํƒ€์ž…์„ ์ง€์›ํ•œ๋‹ค.
  • 8.0 ๋ฒ„์ „์—์„œ๋„ internal_tmp_storage_engine ์‹œ์Šคํ…œ ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•ด MEMORY์™€ TempTable ์ค‘์—์„œ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค. (default = TempTable)
  • TempTable์ด ์ตœ๋Œ€ํ•œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์˜ ํฌ๊ธฐ๋Š” temptable_max_ram ์‹œ์Šคํ…œ ๋ณ€์ˆ˜๋กœ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๊ธฐ๋ณธ๊ฐ’์€ 1GB์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ๋‹ค. ์ž„์‹œ ํ…Œ์ด๋ธ”์˜ ํฌ๊ธฐ๊ฐ€ 1GB๋ณด๋‹ค ์ปค์ง€๋ฉด MySQL ์„œ๋ฒ„๋Š” ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ๋””์Šคํฌ์— ๊ธฐ๋กํ•œ๋‹ค. (์•„๋ž˜ 2๊ฐ€์ง€ ๋ฐฉ์‹)
    • MMAP ํŒŒ์ผ๋กœ ๋””์Šคํฌ์— ๊ธฐ๋ก
    • InnoDB ํ…Œ์ด๋ธ”๋กœ ๊ธฐ๋ก
  • MySQL ์„œ๋ฒ„๊ฐ€ MMAP ํŒŒ์ผ๋กœ ๊ธฐ๋กํ• ์ง€ InnoDB ํ…Œ์ด๋ธ”๋กœ ์ „ํ™˜ํ• ์ง€๋Š” temptable_use_mmap ์‹œ์Šคํ…œ ๋ณ€์ˆ˜๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ธฐ๋ณธ๊ฐ’์€ ON์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ๋‹ค.
    • ์ฆ‰, ๋ฉ”๋ชจ๋ฆฌ์˜ TempTable์˜ ํฌ๊ธฐ๊ฐ€ 1GB๊ฐ€ ๋„˜์œผ๋ฉด MySQL ์„œ๋ฒ„๋Š” ๋ฉ”๋ชจ๋ฆฌ์˜ TempTable์„ MMAP ํŒŒ์ผ๋กœ ์ „ํ™˜ํ•˜๊ฒŒ ๋œ๋‹ค.
    • ๋ฉ”๋ชจ๋ฆฌ์˜ TempTable์„ MMAP ํŒŒ์ผ๋กœ ์ „ํ™˜ํ•˜๋Š” ๊ฒƒ์€ InnoDB ํ…Œ์ด๋ธ”๋กœ ์ „ํ™˜ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์ ๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ๊ฐ’์ด ON์ธ ๊ฒƒ์ด๋‹ค.
    • ์ด ๋•Œ ๋””์Šคํฌ์— ์ƒ์„ฑ๋˜๋Š” ์ž„์‹œ ํ…Œ์ด๋ธ”์€ tmpdir ์‹œ์Šคํ…œ ๋ณ€์ˆ˜์— ์ •์˜๋œ ๋””ํ…ํ„ฐ๋ฆฌ์— ์ €์žฅ๋œ๋‹ค.
  • ์ฒ˜์Œ๋ถ€ํ„ฐ ๋””์Šคํฌ ํ…Œ์ด๋ธ”๋กœ ์ƒ์„ฑ๋˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ internal_tmp_disk_storage_engine ์‹œ์Šคํ…œ ๋ณ€์ˆ˜์— ์„ค์ •๋œ ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์ด ์‚ฌ์šฉ๋œ๋‹ค. (default = InnoDB)

์ฃผ์˜

  • MySQL ์„œ๋ฒ„๋Š” ๋””์Šคํฌ์˜ ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•  ๋•Œ, ํŒŒ์ผ ์˜คํ”ˆ ํ›„ ์ฆ‰์‹œ ํŒŒ์ผ ์‚ญ์ œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ํ•ด๋‹น ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•œ๋‹ค.
    • ์ด๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๊ฐ€ ์ข…๋ฃŒ๋˜๊ฑฐ๋‚˜ ํ•ด๋‹น ์ฟผ๋ฆฌ๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด ์ž„์‹œ ํ…Œ์ด๋ธ”์€ ์ฆ‰์‹œ ์‚ฌ๋ผ์ง€๊ฒŒ ๋ณด์žฅํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
    • ๋˜ํ•œ ์„œ๋ฒ„ ๋‚ด๋ถ€์˜ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ ๋˜๋Š” ์„œ๋ฒ„ ์™ธ๋ถ€์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์œ„ํ•œ ํŒŒ์ผ์„ ๋ณ€๊ฒฝ ๋ฐ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ๋ณผ ์ˆ˜ ์—†๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
  • ์ด ๊ฐ™์€ ์ด์œ ๋กœ ๋””์Šผ์— ์ €์žฅ๋œ ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ์ €์žฅ๋˜๋Š” ํŒŒ์ผ์€ ์šด์˜์ฒด์ œ์˜ dir ๋˜๋Š” ls -al ๊ฐ™์€ ๋ช…๋ น์œผ๋กœ๋Š” ํ™•์ธํ•  ์ˆ˜ ์—†๋‹ค.
    • ๋ฆฌ๋ˆ…์Šค๋‚˜ ์œ ๋‹‰์Šค ๋ช…๋ น์–ด์ธ lsof -p 'pidof mysqld' ๋ช…๋ น์œผ๋กœ ํ™•์ธํ•ด๋„ "deleted"๋กœ ํ‘œ์‹œ๋  ๊ฒƒ์ด๋‹ค.

2-6-2. ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ํ•„์š”ํ•œ ์ฟผ๋ฆฌ

  • ๋Œ€ํ‘œ์ ์ธ ์ผ€์ด์Šค๋“ค
    • ORDER BY์™€ GROUP BY์— ๋ช…์‹œ๋œ ์นผ๋Ÿผ์ด ๋‹ค๋ฅธ ์ฟผ๋ฆฌ
    • ORDER BY๋‚˜ GROUP BY์— ๋ช…์‹œ๋œ ์นผ๋Ÿผ์ด ์กฐ์ธ์˜ ์ˆœ์„œ์ƒ ์ฒซ ๋ฒˆ์งธ ํ…Œ์ด๋ธ”์ด ์•„๋‹Œ ์ฟผ๋ฆฌ
    • DISTINCT์™€ ORDER BY๊ฐ€ ๋™์‹œ์— ์ฟผ๋ฆฌ์— ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ ๋˜๋Š” DISTINCT๊ฐ€ ์ธ๋ฑ์Šค๋กœ ์ฒ˜๋ฆฌ๋˜์ง€ ๋ชปํ•˜๋Š” ์ฟผ๋ฆฌ
    • UNION์ด๋‚˜ UNION DISTINCT๊ฐ€ ์‚ฌ์šฉ๋œ ์ฟผ๋ฆฌ(select_type ์นผ๋Ÿผ์ด UNION RESULT์ธ ๊ฒฝ์šฐ)
    • ์ฟผ๋ฆฌ์˜ ์‹คํ–‰ ๊ณ„ํš์—์„œ select_type์ด DERIVED์ธ ์ฟผ๋ฆฌ
  • Extra ์นผ๋Ÿผ์— "Using temporary" ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋˜๋Š”์ง€ ํ™•์ธํ•˜๋ฉด ์ž„์‹œํ…Œ์ด๋ธ”์ด ์‚ฌ์šฉ๋˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. (์‚ฌ์šฉํ•˜๋”๋ผ๋„ ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์œผ๋‹ˆ ์ฃผ์˜ํ•˜์ž. - 3๋ฒˆ์งธ ์ผ€์ด์Šค)
  • ์œ„์˜ 3๋ฒˆ์งธ ํŒจํ„ด "Using temporary"๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์ง€๋งŒ ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜๋Š” ์ผ€์ด์Šค๋‹ค.

2-6-3. ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ๋””์Šคํฌ์— ์ƒ์„ฑ๋˜๋Š” ๊ฒฝ์šฐ

  • ์•„๋ž˜์˜ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค.
    • UNION์ด๋‚˜ UNION ALL์—์„œ SELECT๋˜๋Š” ์นผ๋Ÿผ ์ค‘์—์„œ ๊ธธ์ด๊ฐ€ 512๋ฐ”์ดํŠธ ์ด์ƒ์˜ ํฌ๊ธฐ์˜ ์นผ๋Ÿผ์ด ์žˆ๋Š” ๊ฒฝ์šฐ
    • GROUP BY๋‚˜ DISTINCT ์นผ๋Ÿผ์—์„œ 512๋ฐ”์ดํŠธ ์ด์ƒ์ธ ํฌ๊ธฐ์˜ ์นผ๋Ÿผ์ด ์žˆ๋Š” ๊ฒฝ์šฐ
    • (MEMORY ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ) ๋ฉ”๋ชจ๋ฆฌ ์ž„์‹œ ํ…Œ์ด๋ธ”์˜ ํฌ๊ธฐ๊ฐ€ tmp_table_size ๋˜๋Š” max_heap_table_size ์‹œ์Šคํ…œ ๋ณ€์ˆ˜๋ณด๋‹ค ํฐ ๊ฒฝ์šฐ
    • (TempTable ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ) ๋ฉ”๋ชจ๋ฆฌ ์ž„์‹œ ํ…Œ์ด๋ธ”์˜ ํฌ๊ธฐ๊ฐ€ temptable_max_ram ์‹œ์Šคํ…œ ๋ณ€์ˆ˜ ๊ฐ’๋ณด๋‹ค ํฐ ๊ฒฝ์šฐ

2-6-4. ์ž„์‹œ ํ…Œ์ด๋ธ” ๊ด€๋ จ ์ƒํƒœ ๋ณ€์ˆ˜

  • ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ๋””์Šคํฌ์— ์ƒ์„ฑ๋๋Š”์ง€ ๋ฉ”๋ชจ๋ฆฌ์— ์ƒ์„ฑ๋๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด MySQL ์„œ๋ฒ„์˜ ์ƒํƒœ ๋ณ€์ˆ˜๋ฅผ ํ™•์ธํ•ด ๋ณด๋ฉด ๋œ๋‹ค.
mysql> FLUSH STATUS;

mysql> SELECT first_name, last_name
       FROM employees
       GROUP BY first_name, last_name;

mysql> SHOW SESSION STATUS LIKE 'Created_tmp%';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 1     |
| Created_tmp_files       | 0     |
| Created_tmp_tables      | 1     |
+-------------------------+-------+
  • Created_tmp_disk_tables: ๋””์Šคํฌ์— ๋‚ด๋ถ€ ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ๋งŒ๋“ค์–ด์ง„ ๊ฐœ์ˆ˜๋งŒ ๋ˆ„์ ํ•ด์„œ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ƒํƒœ ๊ฐ’์ด๋‹ค.
  • Created_tmp_tables: ์ฟผ๋ฆฌ์˜ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ๋งŒ๋“ค์–ด์ง„ ๋‚ด๋ถ€ ์ž„์‹œ ํ…Œ์ด๋ธ”์˜ ๊ฐœ์ˆ˜๋ฅผ ๋ˆ„์ ํ•˜๋Š” ์ƒํƒœ ๊ฐ’์ด๋‹ค. ์ด ๊ฐ’์€ ๋‚ด๋ถ€ ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ๋ฉ”๋ชจ๋ฆฌ์— ๋งŒ๋“ค์–ด์กŒ๋Š”์ง€ ๋””์Šคํฌ์— ๋งŒ๋“ค์–ด์กŒ๋Š”์ง€๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๊ณ  ๋ชจ๋‘ ๋ˆ„์ ํ•œ๋‹ค.

3. ๊ณ ๊ธ‰ ์ตœ์ ํ™”

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

3-1. ์˜ตํ‹ฐ๋งˆ์ด์ € ์Šค์œ„์น˜ ์˜ต์…˜

  • optimizer_switch ์‹œ์Šคํ…œ ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ ์ œ์–ดํ•˜๋ฉฐ, ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์˜ต์…˜์„ ์„ธํŠธ๋กœ ๋ฌถ์–ด์„œ ์„ค์ •ํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • ๊ฐ ์Šค์œ„์น˜ ์˜ต์…˜์€ default, on, off ์ค‘์—์„œ ํ•˜๋‚˜๋ฅผ ๊ณ ๋ฅผ ์ˆ˜ ์žˆ๋‹ค.
์˜ตํ‹ฐ๋งˆ์ด์ € ์Šค์œ„์น˜ ์ด๋ฆ„ ๊ธฐ๋ณธ๊ฐ’ ์„ค๋ช…
batched_key_access off BKA ์กฐ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ฒฐ์ •
block_nested_loop on Block Nested Loop ์กฐ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์„ค์ •
engine_condition_pushdown on Engine Condition Pushdown ๊ธฐ๋Šฅ ์„ค์ •
index_condition_pushdown on Index Condition Pushdown ๊ธฐ๋Šฅ ์„ค์ •
use_index_extensions on Index Extension ์ตœ์ ํ™” ์„ค์ •
index_merge on Index Merge ์ตœ์ ํ™” ์„ค์ •
index_merge_intersection on Index Merge Intersection ์ตœ์ ํ™” ์„ค์ •
index_merge_sort_union on Index Merge Union ์ตœ์ ํ™” ์„ค์ •
mrr on MRR ์ตœ์ ํ™” ์„ค์ •
mrr_cost_based on ๋น„์šฉ ๊ธฐ๋ฐ˜์˜ MRR ์ตœ์ ํ™” ์„ค์ •
semijoin on ์„ธ๋ฏธ ์กฐ์ธ ์ตœ์ ํ™” ์„ค์ •
firstmatch on FirstMatch ์„ธ๋ฏธ ์กฐ์ธ ์ตœ์ ํ™”
loosescan on LooseScan ์„ธ๋ฏธ ์กฐ์ธ ์ตœ์ ํ™” ์„ค์ •
materialization on Materialization ์ตœ์ ํ™” ์„ค์ • (Materialization ์„ธ๋ฏธ ์กฐ์ธ ์ตœ์ ํ™” ํฌํ•จ)
subquery_materialization_cost_based on ๋น„์šฉ ๊ธฐ๋ฐ˜์˜ Materialization ์ตœ์ ํ™” ์„ค์ •
  • ์˜ตํ‹ฐ๋งˆ์ด์ € ์Šค์œ„์น˜ ์˜ต์…˜์€ ๊ธ€๋กœ๋ฒŒ๊ณผ ์„ธ์…˜๋ณ„ ๋ชจ๋‘ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ์Šคํ…œ ๋ณ€์ˆ˜์ด๋ฏ€๋กœ MySQL ์„œ๋ฒ„ ์ „์ฒด์ ์œผ๋กœ ๋˜๋Š” ํ˜„์žฌ ์ปค๋„ฅ์…˜์— ๋Œ€ํ•ด์„œ๋งŒ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Global ์„ค์ •
mysql> SET GLOBAL optimizer_switch='index_merge=on,index_merge_union=on';
  • Session๋ณ„ ์„ค์ •
mysql> SET SESSION optimizer_switch='index_merge=on,index_merge_union=on';
  • ์•„๋ž˜์™€ ๊ฐ™์ด SET_VAR ์˜ตํ‹ฐ๋งˆ์ด์ € ํžŒํŠธ๋ฅผ ์ด์šฉํ•˜๋ฉด ํ˜„์žฌ ์ฟผ๋ฆฌ์—๋งŒ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
mysql> SELECT /*+ SET_VAR(optimizer_switch='condition_fanout_filter=off') */ 
         * 
       FROM employees
       LIMIT 1;
+--------+------------+------------+-----------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date  |
+--------+------------+------------+-----------+--------+------------+
|  10001 | 1953-09-02 | Georgi     | Facello   | M      | 1986-06-26 |
+--------+------------+------------+-----------+--------+------------+
1 row in set (0.00 sec)

3-1-1. MRR๊ณผ ๋ฐฐ์น˜ ํ‚ค ์—‘์„ธ์Šค(mmr & batched_key_access)

  • MRR(Multi-Range Read)๋Š” DS-MRR(Disk Sweep Multi-Range Read)์ด๋ผ๊ณ ๋„ ๋ถ€๋ฅธ๋‹ค.
  • MySQL ์„œ๋ฒ„์—์„œ ์ง€๊ธˆ๊นŒ์ง€ ์ง€์›ํ•˜๋˜ ์กฐ์ธ ๋ฐฉ์‹์€ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ํ•œ ๊ฑด ์ฝ์–ด์„œ ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”์˜ ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฐพ์•„์„œ ์กฐ์ธ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด์—ˆ๋‹ค.
    • ์ด๋ฅผ ๋„ค์Šคํ‹ฐ๋“œ ๋ฃจํ”„ ์กฐ์ธ Nested Loop Join์ด๋ผ๊ณ  ํ•œ๋‹ค.
    • MySQL ์„œ๋ฒ„ ๋‚ด๋ถ€ ๊ตฌ์กฐ์ƒ ์กฐ์ธ ์ฒ˜๋ฆฌ๋Š” MySQL ์—”์ง„์ด ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ, ์‹ค์ œ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์ฝ๋Š” ๋ถ€๋ถ„์€ ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์ด ๋‹ด๋‹นํ•œ๋‹ค.
    • ์ด๋•Œ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ ๊ฑด๋ณ„๋กœ ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฐพ์œผ๋ฉด ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฐพ๊ณ  ์ฝ๋Š” ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์—์„œ๋Š” ์•„๋ฌด๋Ÿฐ ์ตœ์ ํ™”๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค.
  • ์ด ๊ฐ™์€ ๋‹จ์ ์„ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด MySQL ์„œ๋ฒ„๋Š” ์กฐ์ธ ๋Œ€์ƒ ํ…Œ์ด๋ธ” ์ค‘ ํ•˜๋‚˜๋กœ๋ถ€ํ„ฐ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฝ์–ด์„œ ์กฐ์ธ ๋ฒ„ํผ์— ๋ฒ„ํผ๋งํ•œ๋‹ค.
    • ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฝ์–ด์„œ ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”๊ณผ์˜ ์กฐ์ธ์„ ์ฆ‰์‹œ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  ์กฐ์ธ ๋Œ€์ƒ์„ ๋ฒ„ํผ๋งํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
    • ์กฐ์ธ ๋ฒ„ํผ์— ๋ ˆ์ฝ”๋“œ๊ฐ€ ๊ฐ€๋“ ์ฐจ๋ฉด MySQL ์—”์ง„์€ ๋ฒ„ํผ๋ง๋œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์œผ๋กœ ํ•œ ๋ฒˆ์— ์š”์ฒญํ•œ๋‹ค.
    • ์ด๋ฅผ ํ†ตํ•ด ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์€ ์ฝ์–ด์•ผํ•  ๋ ˆ์ฝ”๋“œ๋“ค์„ ๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€์— ์ •๋ ฌ๋œ ์ˆœ์„œ๋กœ ์ ‘๊ทผํ•ด์„œ ๋””์Šคํฌ์˜ ๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€ ์ฝ๊ธฐ๋ฅผ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.
    • ๋ฌผ๋ก  ๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ(InnoDB ๋ฒ„ํผ ํ’€)์— ์žˆ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ ๋ฒ„ํผ ํ’€์˜ ์ ‘๊ทผ์„ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.
  • MMR์„ ์‘์šฉํ•ด์„œ ์‹คํ–‰๋˜๋Š” ์กฐ์ธ ๋ฐฉ์‹์ธ BKA ์กฐ์ธ ์ตœ์ ํ™” ๋ฐฉ์‹๋„ ์žˆ๋Š”๋ฐ ๊ธฐ๋ณธ๊ฐ’์ด off์ด๋‹ค.
    • ๊ทธ ์ด์œ ๋Š” BKA ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ถ€๊ฐ€์ ์ธ ์ •๋ ฌ ์ž‘์—…์ด ํ•„์š”ํ•ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์ด ์•ˆ ์ข‹์•„์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋‹จ์ ์ด ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
    • ํ•˜์ง€๋งŒ ๋„์›€์ด ๋˜๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค.

3-1-2. ๋ธ”๋ก ๋„ค์Šคํ‹ฐ๋“œ ๋ฃจํ”„ ์กฐ์ธ(block_nested_loop)

์ฃผ์˜

MySQL 8.0.18 ๋ฒ„์ „๋ถ€ํ„ฐ ํ•ด์‹œ ์กฐ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋„์ž…๋˜์—ˆ๊ณ , MySQL 8.0.20 ๋ฒ„์ „๋ถ€ํ„ฐ๋Š” ๋ธ”๋ก ๋„ค์Šคํ‹ฐ๋“œ ์กฐ์ธ์€ ๋”์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š๊ณ  ํ•ด์‹œ ์กฐ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋Œ€์ฒด๋œ๋‹ค. ๋”ฐ๋ผ์„œ Extra ์นผ๋Ÿผ์— "Using Join Buffer(block nested loop)" ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.

  • MySQL์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์กฐ์ธ์ด ๋„ค์Šคํ‹ฐ๋“œ ๋ฃจํ”„ ์กฐ์ธ์ด๋‹ค.
    • ์กฐ์ธ์˜ ์—ฐ๊ฒฐ ์กฐ๊ฑด์ด ๋˜๋Š” ์นผ๋Ÿผ์— ๋ชจ๋‘ ์ธ๋ฑ์Šค๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ๋˜๋Š” ์กฐ์ธ ๋ฐฉ์‹์ด๋‹ค.
  • ๋งˆ์น˜ ์ค‘์ฒฉ๋œ ๋ฐ˜๋ณต ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ž‘๋™ํ•œ๋‹ค๊ณ  ํ•˜์—ฌ ๋„ค์Šคํ‹ฐ๋“œ ๋ฃจํ”„ ์กฐ์ธ์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.
mysql> EXPLAIN
       SELECT *
       FROM employees e
       INNER JOIN salaries s ON s.emp_no = e.emp_no
       AND s.from_date <= NOW()
       AND s.to_date >= NOW()
       WHERE e.first_name = 'Amor';
+----+-------------+------+--------------+------+----------+-------------+
| id | select_type | type | key          | rows | filtered | Extra       |
+----+-------------+------+--------------+------+----------+-------------+
|  1 | SIMPLE      | ref  | ix_firstname |    1 |   100.00 | NULL        |
|  1 | SIMPLE      | ref  | PRIMARY      |    9 |    11.11 | Using where |
+----+-------------+------+--------------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
  • ๋„ค์Šคํ‹ฐ๋“œ ๋ฃจํ”„ ์กฐ์ธ๊ณผ ๋ธ”๋ก ๋„ค์Šคํ‹ฐ๋“œ ๋ฃจํ”„ ์กฐ์ธ(Block Nested Loop Join)์˜ ๊ฐ€์žฅ ํฐ ์ฐจ์ด๋Š” ์กฐ์ธ ๋ฒ„ํผ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š”์ง€ ์—ฌ๋ถ€์™€ ์กฐ์ธ์—์„œ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”๊ณผ ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”์ด ์–ด๋–ค ์ˆœ์„œ๋กœ ์กฐ์ธ๋˜๋А๋ƒ์ด๋‹ค.
  • ์กฐ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ "Block"์ด๋ผ๋Š” ๋‹จ์–ด๊ฐ€ ์‚ฌ์šฉ๋˜๋ฉด ์กฐ์ธ์šฉ์œผ๋กœ ๋ณ„๋„์˜ ๋ฒ„ํผ๊ฐ€ ์‚ฌ์šฉ๋๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋Š”๋ฐ, ์กฐ์ธ ์ฟผ๋ฆฌ์˜ ์‹คํ–‰ ๊ณ„ํš์—์„œ Extra ์นผ๋Ÿผ์— "Using Join buffer"๋ผ๋Š” ๋ฌธ๊ตฌ๊ฐ€ ํ‘œ์‹œ๋˜๋ฉด ๊ทธ ์‹คํ–‰ ๊ณ„ํš์€ ์กฐ์ธ ๋ฒ„ํผ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
  • ์กฐ์ธ์€ ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”์—์„œ ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ์˜ ๊ฑด์ˆ˜๋งŒํผ ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”์„ ๊ฒ€์ƒ‰ํ•˜๋ฉด์„œ ์ฒ˜๋ฆฌ๋œ๋‹ค. ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”์€ ํ•œ ๋ฒˆ์— ์ญ‰ ์ฝ์ง€๋งŒ, ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”์€ ์—ฌ๋Ÿฌ ๋ฒˆ ์ฝ๋Š”๋‹ค.
    • ex) ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”์— ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ 1,000๊ฑด. ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”์˜ ์กฐ์ธ ์กฐ๊ฑด์ด ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์—†์—ˆ๋‹ค๋ฉด ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”์—์„œ ์—ฐ๊ฒฐ๋˜๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด 1,000๋ฒˆ์˜ ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์„ ํ•ด์•ผ ํ•œ๋‹ค.
    • ๊ทธ๋ž˜์„œ ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”์„ ๊ฒ€์ƒ‰ํ•  ๋•Œ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ์ฟผ๋ฆฌ๋Š” ์ƒ๋‹นํžˆ ๋А๋ ค์ง€๋ฉฐ, ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ์ตœ๋Œ€ํ•œ ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”์˜ ๊ฒ€์ƒ‰์ด ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ์‹คํ–‰ ๊ณ„ํš์„ ์ˆ˜๋ฆฝํ•œ๋‹ค.
  • ๊ทธ๋Ÿฐ๋ฐ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ๋“  ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”์˜ ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์ด๋‚˜ ์ธ๋ฑ์Šค ํ’€ ์Šค์บ”์„ ํ”ผํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ๋“œ๋ผ์ด๋น™ ํ…Œ์ด๋ธ”์—์„œ ์ฝ์€ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์บ์‹œํ•œ ํ›„ ๋“œ๋ฆฌ๋ธ ํ…Œ์ด๋ธ”๊ณผ ์ด ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ๋ฅผ ์กฐ์ธํ•˜๋Š” ํ˜•ํƒœ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ์ด ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ์˜ ์บ์‹œ๋ฅผ ์กฐ์ธ ๋ฒ„ํผ Join Buffer๋ผ๊ณ  ํ•œ๋‹ค.
    • ์กฐ์ธ ๋ฒ„ํผ๋Š” join_buffer_size๋ผ๋Š” ์‹œ์Šคํ…œ ๋ณ€์ˆ˜๋กœ ํฌ๊ธฐ๋ฅผ ์ œํ•œํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์กฐ์ธ์ด ์™„๋ฃŒ๋˜๋ฉด ์กฐ์ธ ๋ฒ„ํผ๋Š” ๋ฐ”๋กœ ํ•ด์ œ๋œ๋‹ค.
  • ์•„๋ž˜ ์กฐ์ธ์˜ ์˜ˆ์ œ๋Š” ๊ฐ ํ…Œ์ด๋ธ”์— ๋Œ€ํ•œ ์กฐ๊ฑด WHERE๋Š” ์žˆ์ง€๋งŒ, ๋‘ ํ…Œ์ด๋ธ” ๊ฐ„์˜ ์—ฐ๊ฒฐ ๊ณ ๋ฆฌ ์—ญํ• ์„ ํ•˜๋Š” ์กฐ์ธ ์กฐ๊ฑด์€ ์—†๋‹ค.
    • ๋”ฐ๋ผ์„œ dept_emp ํ…Œ์ด๋ธ”์—์„œ from_date>'2000-01-01'์ธ ๋ ˆ์ฝ”๋“œ(10,616๊ฑด)์™€ employees ํ…Œ์ด๋ธ”์—์„œ emp_no<109004 ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋ ˆ์ฝ”๋“œ(99,003๊ฑด)๋Š” ์นดํ…Œ์‹œ์•ˆ ์กฐ์ธ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
mysql> EXPLAIN
       SELECT *
       FROM dept_emp de, employees e
       WHERE de.from_date > '1995-01-01' AND e.emp_no < 109004;
+----+-------------+-------+-------+---------+--------+----------+--------------------------------------------+
| id | select_type | table | type  | key     | rows   | filtered | Extra                                      |
+----+-------------+-------+-------+---------+--------+----------+--------------------------------------------+
|  1 | SIMPLE      | e     | range | PRIMARY | 150070 |   100.00 | Using where                                |
|  1 | SIMPLE      | de    | ALL   | NULL    | 331143 |    50.00 | Using where; Using join buffer (hash join) |
+----+-------------+-------+-------+---------+--------+----------+--------------------------------------------+
2 rows in set, 1 warning (0.01 sec)
  • ์‹คํ–‰ ๊ณ„ํš์„ ์‚ดํŽด๋ณด๋ฉด "Using Join Buffer(block nested loop)" ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜์ง€ ์•Š๊ณ  "Using Join Buffer(hash join)"์œผ๋กœ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ฃผ์˜์—์„œ ๋ณด์—ฌ์ค€ ๊ฒƒ์ฒ˜๋Ÿผ ํ•ด์‹œ ์กฐ์ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ๋„์ž…๋๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 8.0.20 ๋ฒ„์ „ ์ด์ „์ด๋ผ๋ฉด "Using join buffer (block nested loop)"๋ผ๋Š” ๋ฌธ๊ตฌ๊ฐ€ ์ถœ๋ ฅ๋์„ ๊ฒƒ์ด๋‹ค.
  • ์œ„ ์ฟผ๋ฆฌ๋Š” ์•„๋ž˜์˜ ๊ณผ์ •์„ ๊ฑฐ์ณ ์‹คํ–‰๋œ๋‹ค. (block nested loop join์˜ ๊ฒฝ์šฐ)
    1. dept_emp ํ…Œ์ด๋ธ”์˜ ix_fromdate ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•ด(from_date > '1995-01-01') ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•œ๋‹ค.
    2. ์กฐ์ธ์— ํ•„์š”ํ•œ ๋‚˜๋จธ์ง€ ์นผ๋Ÿผ์„ ๋ชจ๋‘ dept_emp ํ…Œ์ด๋ธ”๋กœ๋ถ€ํ„ฐ ์ฝ์–ด์„œ ์กฐ์ธ ๋ฒ„ํผ์— ์ €์žฅํ•œ๋‹ค.
    3. employees ํ…Œ์ด๋ธ”์˜ ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค๋ฅผ ์ด์šฉํ•ด (emp_no < 109004) ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•œ๋‹ค.
    4. 3๋ฒˆ์—์„œ ๊ฒ€์ƒ‰๋œ ๊ฒฐ๊ณผ(employees)์— 2๋ฒˆ์˜ ์บ์‹œ๋œ ์กฐ์ธ ๋ฒ„ํผ์˜ ๋ ˆ์ฝ”๋“œ(dept_emp)๋ฅผ ๊ฒฐํ•ฉํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

3-1-3. ์ธ๋ฑ์Šค ์ปจ๋””์…˜ ํ‘ธ์‹œ๋‹ค์šด(index_condition_pushdown)

  • MySQL 5.6 ๋ฒ„์ „๋ถ€ํ„ฐ ๋„์ž…๋œ ๊ธฐ๋Šฅ, ์ฟผ๋ฆฌ์˜ ์„ฑ๋Šฅ์„ ๋ช‡ ๋ฐฐ์—์„œ ๋ช‡์‹ญ ๋ฐฐ๋กœ ํ–ฅ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ์ด๋‹ค.
  • ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค. (๊ธฐ๋ณธ๊ฐ’์€ on์ด๋‹ค.)
# on
mysql> SET optimizer_switch='index_condition_pushdown=on';
# off
mysql> SET optimizer_switch='index_condition_pushdown=off';
  • ๋จผ์ € ๋น„ํ™œ์„ฑํ™”ํ•ด์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด์ž.
mysql> ALTER TABLE employees ADD INDEX ix_lastname_firstname (last_name, first_name);
Query OK, 0 rows affected (0.67 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SET optimizer_switch='index_condition_pushdown=off';
mysql> SHOW VARIABLES LIKE 'optimizer_switch' \G
*************************** 1. row ***************************
Variable_name: optimizer_switch
        Value: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=off,skip_scan=on,hash_join=on,subquery_to_derived=off,prefer_ordering_index=on,hypergraph_optimizer=off,derived_condition_pushdown=on
1 row in set (0.00 sec)
  • ์ด์ œ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์ด ๋ช‡ ๊ฑด์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฝ๋Š”์ง€๋ฅผ ์‚ดํŽด๋ณด์ž.
mysql> EXPLAIN 
       SELECT * FROM employees WHERE last_name='Acton' AND first_name LIKE '%sal';
+----+-------------+-----------+------+-----------------------+---------+------+----------+-------------+
| id | select_type | table     | type | key                   | key_len | rows | filtered | Extra       |
+----+-------------+-----------+------+-----------------------+---------+------+----------+-------------+
|  1 | SIMPLE      | employees | ref  | ix_lastname_firstname | 66      |  189 |    11.11 | Using where |
+----+-------------+-----------+------+-----------------------+---------+------+----------+-------------+
  • "Using where"๋ผ๊ณ  ํ‘œ์‹œ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

    • "Using where"๋Š” InnoDB ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์ด ์ฝ์–ด์„œ ๋ฐ˜ํ™˜ํ•ด์ค€ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” WHERE ์กฐ๊ฑด์— ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์‚ฌํ•˜๋Š” ๊ณผ์ •์„ ์˜๋ฏธํ•œ๋‹ค.
    • ์ด ์ฟผ๋ฆฌ์—์„œ๋Š” first_name LIKE '%sal'์ด ๊ฒ€์‚ฌ ๊ณผ์ •์—์„œ ์‚ฌ์šฉ๋œ ์กฐ๊ฑด์ด๋‹ค.
  • ์•„๋ž˜ ๊ทธ๋ฆผ์€ last_name='Anton' ์กฐ๊ฑด์œผ๋กœ ์ธ๋ฑ์Šค ๋ ˆ์ธ์ง€ ์Šค์บ”์„ ํ•˜๊ณ  ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฝ์€ ํ›„, first_name LIKE '%sal' ์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๋น„๊ตํ•˜๋Š” ๊ณผ์ •์„ ํ‘œํ˜„ํ•œ ๊ฒƒ์ด๋‹ค.

    • ์„ฑ๋Šฅ๊ณผ ํฐ ๊ด€๊ณ„๊ฐ€ ์—†์–ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์‚ฌ์‹ค ์ด ๊ณผ์ •์€ ๋งค์šฐ ์ค‘์š”ํ•œ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง„๋‹ค.
    • ์‹ค์ œ ํ…Œ์ด๋ธ”์„ ์ฝ์–ด์„œ 3๊ฑด์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฐ€์ ธ์™”์ง€๋งŒ ๊ทธ์ค‘ ๋‹จ 1๊ฑด๋งŒ first_name LIKE '%sal' ์กฐ๊ฑด์— ์ผ์น˜ํ–ˆ๋‹ค.
    • ๊ทธ๋Ÿฐ๋ฐ ๋งŒ์•ฝ last_name ์กฐ๊ฑด์— ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๊ฐ€ 10๋งŒ ๊ฑด์ด๊ณ , ๊ทธ์ค‘์—์„œ first_name ์กฐ๊ฑด์— ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋‹จ 1๊ฑด๋งŒ ์žˆ๋‹ค๋ฉด ์–ด๋–จ๊นŒ? => 99,999๊ฑด์˜ ๋ ˆ์ฝ”๋“œ ์ฝ๊ธฐ๊ฐ€ ๋ถˆํ•„์š”ํ•œ ์ž‘์—…์ด ๋œ๋‹ค.

  • MySQL 5.6 ๋ฒ„์ „๋ถ€ํ„ฐ๋Š” ์ด๋ ‡๊ฒŒ ์ธ๋ฑ์Šค๋ฅผ ๋ฒ”์œ„ ์ œํ•œ ์กฐ๊ฑด์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ ์ธ๋ฑ์Šค์— ํฌํ•จ๋œ ์กฐ๊ฑด์ด ์žˆ๋‹ค๋ฉด ๋ชจ๋‘ ๋ชจ์•„์„œ ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ธ๋“ค๋Ÿฌ API๊ฐ€ ๊ฐœ์„ ๋๋‹ค.
    • ๋”ฐ๋ผ์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•ด ์ตœ๋Œ€ํ•œ ํ•„ํ„ฐ๋ง๊นŒ์ง€ ์™„๋ฃŒํ•ด์„œ ๊ผญ ํ•„์š”ํ•œ ๋ ˆ์ฝ”๋“œ 1๊ฑด์— ๋Œ€ํ•ด์„œ๋งŒ ํ…Œ์ด๋ธ” ์ฝ๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•  ๊ฒƒ์ด๋‹ค.
    • ์‹คํ–‰๊ณ„ํš์„ ํ™•์ธํ•ด๋ณด๋ฉด "Using where"์ด ์•„๋‹ˆ๋ผ "Using index condition"์ด๋ผ๋Š” ๋ฌธ๊ตฌ๊ฐ€ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
SET optimizer_switch='index_condition_pushdown=on';

mysql> EXPLAIN 
       SELECT * FROM employees WHERE last_name='Acton' AND first_name LIKE '%sal';
+----+-------------+-----------+------+-----------------------+---------+------+----------+-----------------------+
| id | select_type | table     | type | key                   | key_len | rows | filtered | Extra                 |
+----+-------------+-----------+------+-----------------------+---------+------+----------+-----------------------+
|  1 | SIMPLE      | employees | ref  | ix_lastname_firstname | 66      |  189 |    11.11 | Using index condition |
+----+-------------+-----------+------+-----------------------+---------+------+----------+-----------------------+

3-1-4. ์ธ๋ฑ์Šค ํ™•์žฅ(use_index_extensions)

  • InnoDB ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์„ ์‚ฌ์šฉํ•˜๋Š” ํ…Œ์ด๋ธ”์—์„œ ์„ธ์ปจ๋”๋ฆฌ ์ธ๋ฑ์Šค์— ์ž๋™์œผ๋กœ ์ถ”๊ฐ€๋œ ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ• ์ง€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ์˜ต์…˜
  • "์„ธ์ปจ๋”๋ฆฌ ์ธ๋ฑ์Šค์— ์ž๋™์œผ๋กœ ์ถ”๊ฐ€๋œ ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค"์˜ ์˜๋ฏธ์™€ ์ด๋กœ ์ธํ•œ ์„ฑ๋Šฅ์ƒ์˜ ์žฅ์ ?
  • InnoDB ์Šคํ† ๋ฆฌ์ง€ ์—”์ง„์€ ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค๋ฅผ ํด๋Ÿฌ์Šคํ„ฐ๋ง ํ‚ค๋กœ ์ƒ์„ฑํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ๋ชจ๋“  ์„ธ์ปจ๋”๋ฆฌ ์ธ๋ฑ์Šค๋Š” ๋ฆฌํ”„ ๋…ธ๋“œ์— ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค ๊ฐ’์„ ๊ฐ€์ง„๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค๊ฐ€ (dept_no, emp_no)์™€ ๊ฐ™์ด ๋˜์–ด ์žˆ๋Š” ํ…Œ์ด๋ธ”์— from_date ์นผ๋Ÿผ์— ๋Œ€ํ•ด ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ฉด (dept_no, emp_no, from_date) ์กฐํ•ฉ์œผ๋กœ ์ธ๋ฑ์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๊ณผ ํก์‚ฌํ•˜๊ฒŒ ์ž‘๋™ํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.
  • MySQL ์„œ๋ฒ„๊ฐ€ ์—…๊ทธ๋ ˆ์ด๋“œ ๋˜๋ฉด์„œ ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ix_fromdate ์ธ๋ฑ์Šค์˜ ๋งˆ์ง€๋ง‰์— (dept_no, emp_no) ์นผ๋Ÿผ์ด ์ˆจ์–ด์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ธ์ง€ํ•˜๊ณ  ์‹คํ–‰ ๊ณ„ํš์„ ์ˆ˜๋ฆฝํ•˜๋„๋ก ๊ฐœ์„ ๋๋‹ค.
    • ์˜ˆ์ „ ๋ฒ„์ „์˜ MySQL ๋ฒ„์ „์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์ฟผ๋ฆฌ๊ฐ€ ์„ธ์ปจ๋”๋ฆฌ ์ธ๋ฑ์Šค์˜ ๋งˆ์ง€๋ง‰์— ์ž๋™ ์ถ”๊ฐ€๋˜๋Š” ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค๋ฅผ ์ œ๋Œ€๋กœ ํ™œ์šฉํ•˜์ง€ ๋ชปํ–ˆ์—ˆ๋‹ค.
mysql> EXPLAIN SELECT COUNT(*) FROM dept_emp WHERE from_date='1987-07-25' AND dept_no='d001';
+----+-------------+----------+------+-------------+---------+-------------+
| id | select_type | table    | type | key         | key_len | Extra       |
+----+-------------+----------+------+-------------+---------+-------------+
|  1 | SIMPLE      | dept_emp | ref  | ix_fromdate | 19      | Using index |
+----+-------------+----------+------+-------------+---------+-------------+
  • ์‹คํ–‰ ๊ณ„ํš์˜ key_len ์นผ๋Ÿผ์€ ์ด ์ฟผ๋ฆฌ๊ฐ€ ์ธ๋ฑ์Šค๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ์นผ๋Ÿผ ์ค‘์—์„œ ์–ด๋А ๋ถ€๋ถ„(์–ด๋А ์นผ๋Ÿผ)๊นŒ์ง€ ์‚ฌ์šฉํ–ˆ๋Š”์ง€๋ฅผ ๋ฐ”์ดํŠธ ์ˆ˜๋กœ ๋ณด์—ฌ์ฃผ๋Š”๋ฐ, ์ด ์˜ˆ์ œ์—์„œ๋Š” 19๋ฐ”์ดํŠธ๊ฐ€ ํ‘œ์‹œ๋˜์—ˆ๋‹ค.
    • ์ด๋Š” from_date ์นผ๋Ÿผ(3๋ฐ”์ดํŠธ)๊ณผ dept_emp ์นผ๋Ÿผ(16๋ฐ”์ดํŠธ)๊นŒ์ง€ ์‚ฌ์šฉํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ์œ ์ถ”ํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.
mysql> EXPLAIN SELECT COUNT(*) FROM dept_emp WHERE from_date='1987-07-25';
+----+-------------+----------+------+-------------+---------+-------------+
| id | select_type | table    | type | key         | key_len | Extra       |
+----+-------------+----------+------+-------------+---------+-------------+
|  1 | SIMPLE      | dept_emp | ref  | ix_fromdate | 3       | Using index |
+----+-------------+----------+------+-------------+---------+-------------+
  • ๋ฐ˜๋ฉด "dept_no='d001'" ์กฐ๊ฑด์„ ์ œ๊ฑฐํ•œ ์ฟผ๋ฆฌ์˜ ์‹คํ–‰ ๊ณ„ํš์—์„œ๋Š” ์œ„์™€ ๊ฐ™์ด from_date ์นผ๋Ÿผ์„ ์œ„ํ•œ 3๋ฐ”์ดํŠธ๋งŒ ํ‘œ์‹œ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
    • from_date์€ DATE ํƒ€์ž…(3byte)์ด๋‹ค.

3-1-5. ์ธ๋ฑ์Šค ๋จธ์ง€(index_merge)

  • ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•ด ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ, ๋Œ€๋ถ€๋ถ„ ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ํ…Œ์ด๋ธ” ๋ณ„๋กœ ํ•˜๋‚˜์˜ ์ธ๋ฑ์Šค๋งŒ ์‚ฌ์šฉํ•˜๋„๋ก ์‹คํ–‰๊ณ„ํš์„ ์ˆ˜๋ฆฝํ•œ๋‹ค.
  • ํ•˜์ง€๋งŒ ์ธ๋ฑ์Šค ๋จธ์ง€ ์‹คํ–‰ ๊ณ„ํš์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํ•˜๋‚˜์˜ ํ…Œ์ด๋ธ”์— ๋Œ€ํ•ด 2๊ฐœ ์ด์ƒ์˜ ์ธ๋ฑ์Šค๋ฅผ ์ด์šฉํ•ด ์ฟผ๋ฆฌ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  • ๋ณดํ†ต ์ธ๋ฑ์Šค๋ฅผ ํ•˜๋‚˜๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํšจ์œจ์ ์ด๋‚˜ ์‚ฌ์šฉ๋œ ๊ฐ๊ฐ์˜ ์กฐ๊ฑด์ด ์„œ๋กœ ๋‹ค๋ฅธ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ  ๊ทธ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๊ฐ€ ๋งŽ์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋  ๋•Œ MySQL ์„œ๋ฒ„๋Š” ์ธ๋ฑ์Šค ๋จธ์ง€ ์‹คํ–‰ ๊ณ„ํš์„ ์„ ํƒํ•œ๋‹ค.
  • ์ธ๋ฑ์Šค ๋จธ์ง€ ์‹คํ–‰ ๊ณ„ํš์€ 3๊ฐœ์˜ ์„ธ๋ถ€ ์‹คํ–‰ ๊ณ„ํš์œผ๋กœ ๋‚˜๋ˆ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. 3๊ฐ€์ง€ ์ตœ์ ํ™” ๋ชจ๋‘ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•ด ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค๋Š” ๊ฒƒ์€ ๋™์ผํ•˜์ง€๋งŒ ๊ฐ๊ฐ์˜ ๊ฒฐ๊ณผ๋ฅผ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ๋ณ‘ํ•ฉํ• ์ง€์— ๋”ฐ๋ผ ๊ตฌ๋ถ„๋œ๋‹ค.
    • index_merge_intersection
    • index_merge_sort_union
    • index_merge_union
  • index_merge ์˜ตํ‹ฐ๋งˆ์ด์ € ์˜ต์…˜๋„ ์กด์žฌํ•˜๋Š”๋ฐ, ์œ„์˜ 3๊ฐœ์˜ ์ตœ์ ํ™” ์˜ต์…˜์€ ํ•œ ๋ฒˆ์— ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์ด๋‹ค.

3-1-6. ์ธ๋ฑ์Šค ๋จธ์ง€ - ๊ต์ง‘ํ•ฉ(index_merge_intersection)

  • ์•„๋ž˜์˜ ์˜ˆ์‹œ๋ฅผ ๋ณด์ž.
    • first_name์€ ix_firstname ์ธ๋ฑ์Šค
    • emp_no๋Š” PRIMARY ์ธ๋ฑ์Šค
mysql> EXPLAIN
       SELECT *
       FROM employees
       WHERE first_name='Georgi' AND emp_no BETWEEN 10000 AND 20000;
+-------------+----------------------+---------+------+----------------------------------------------------+
| type        | key                  | key_len | rows | Extra                                              |
+-------------+----------------------+---------+------+----------------------------------------------------+
| index_merge | ix_firstname,PRIMARY | 62,4    |    1 | Using intersect(ix_firstname,PRIMARY); Using where |
+-------------+----------------------+---------+------+----------------------------------------------------+
1 row in set, 1 warning (0.01 sec)
  • 2๊ฐœ์˜ ์ธ๋ฑ์Šค ์ค‘ ์–ด๋–ค ์กฐ๊ฑด์„ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” 2๊ฐœ์˜ ์ธ๋ฑ์Šค๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•ด์„œ ์ฟผ๋ฆฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๋‹ค.
    • Extra์— "Using intersect(ix_firstname,PRIMARY)"๋ผ๊ณ  ๋ณด์ด๋Š” ๊ฒƒ์ด ์ธ๋ฑ์Šค๋ฅผ ๊ฐ๊ฐ ๊ฒ€์ƒ‰ํ•ด์„œ ๊ทธ ๊ฒฐ๊ณผ์˜ ๊ต์ง‘ํ•ฉ๋งŒ ๋ฐ˜ํ™˜ํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
  • ๋‘ ๊ฐ€์ง€ ์กฐ๊ฑด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ถฉ๋ถ„ํžˆ ํšจ์œจ์ ์œผ๋กœ ์ฟผ๋ฆฌ๋ฅด ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค๋ฉด ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” 2๊ฐœ์˜ ์ธ๋ฑ์Šค๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๋Š” ์‹คํ–‰ ๊ณ„ํš์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๊ฒƒ์ด๋‹ค.
    • ์ฆ‰, ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ๊ฐ๊ฐ์˜ ์กฐ๊ฑด์— ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๋ฅผ ์˜ˆ์ธกํ•ด ๋ณธ ๊ฒฐ๊ณผ, ๋‘ ์กฐ๊ฑด ๋ชจ๋‘ ์ƒ๋Œ€์ ์œผ๋กœ ๋งŽ์€ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋œ ๊ฒƒ์ด๋‹ค.
mysql> SELECT COUNT(*) FROM employees WHERE first_name='Georgi';
+----------+
| COUNT(*) |
+----------+
|      253 |
+----------+

mysql> SELECT COUNT(*) FROM employees WHERE emp_no BETWEEN 10000 AND 20000;
+----------+
| COUNT(*) |
+----------+
|    10000 |
+----------+
  • ๋งŒ์•ฝ ์ธ๋ฑ์Šค ๋จธ์ง€ ์‹คํ–‰ ๊ณ„ํš์ด ์•„๋‹ˆ์—ˆ๋‹ค๋ฉด 2๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ–ˆ์„ ๊ฒƒ์ด๋‹ค.
  1. "first_name='Georgi'" ์กฐ๊ฑด๋งŒ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ 253๊ฑด์„ ๊ฒ€์ƒ‰ํ•œ ๋‹ค์Œ ๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€์—์„œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฐพ๊ณ  emp_no ์นผ๋Ÿผ์˜ ์กฐ๊ฑด์— ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋“ค๋งŒ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ˜•ํƒœ๋กœ ์ฒ˜๋ฆฌ๋ผ์•ผ ํ•œ๋‹ค.
  2. "emp_no BETWEEN 10000 AND 20000" ์กฐ๊ฑด๋งŒ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค๋ฅผ ์ด์šฉํ•ด 10,000๊ฑด์„ ์ฝ์–ด์™€์„œ "first_name='Georgi'" ์กฐ๊ฑด์— ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋งŒ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ˜•ํƒœ๋กœ ์ฒ˜๋ฆฌ๋ผ์•ผ ํ•œ๋‹ค.
  • ๋ฐ˜๋ฉด ๋‘ ์กฐ๊ฑด์„ ๋ชจ๋‘ ๋งŒ์กฑํ•˜๋Š” ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๋Š” 14๊ฑด๋ฐ–์— ์•ˆ๋œ๋‹ค.
    • ์œ„์˜ ๋‘ ์กฐ๊ฑด์—์„œ ๊ฒฐ๊ตญ ์˜๋ฏธ ์žˆ๋Š” ์กฐํšŒ๋Š” ์ „์ฒด ์ค‘ 14๊ฑด๋งŒ ์žˆ๋‹ค๋Š” ๋œป์ด๋‹ค. => ๋น„ํšจ์œจ์ด ํฐ ์ƒํ™ฉ์ด์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ๊ฐ ์ธ๋ฑ์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•ด ๋‘ ๊ฒฐ๊ณผ์˜ ๊ต์ง‘ํ•ฉ๋งŒ ์ฐพ์•„์„œ ๋ฐ˜ํ™˜ํ•œ ๊ฒƒ์ด๋‹ค.
mysql> SELECT COUNT(*) FROM employees
       WHERE first_name='Georgi' AND emp_no BETWEEN 10000 AND 20000;
+----------+
| COUNT(*) |
+----------+
|       14 |
+----------+
  • ix_firstname ์ธ๋ฑ์Šค๋Š” ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค์ธ emp_no ์นผ๋Ÿผ์„ ์ž๋™์œผ๋กœ ํฌํ•จํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ƒฅ ix_firstname ์ธ๋ฑ์Šค๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์„ฑ๋Šฅ์ด ์ข‹์„ ๊ฒƒ์œผ๋กœ ์ƒ๊ฐํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
    • ๊ทธ๋ ‡๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด index_merge_intersection์„ ๋น„ํ™œ์„ฑํ™”ํ•ด๋ผ.
    • ์„œ๋ฒ„ ์ „์ฒด์ ์œผ๋กœ ํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ์•ˆํ•˜๋‹ค๋ฉด ํ˜„์žฌ ์ปค๋„ฅ์…˜ ๋˜๋Š” ํ˜„์žฌ ์ฟผ๋ฆฌ์— ๋Œ€ํ•ด์„œ๋งŒ ์ตœ์ ํ™”๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ๊ฒƒ๋„ ๋ฐฉ๋ฒ•์ด๋‹ค.
mysql> SET GLOBAL optimizer_switch='index_merge_intersection=off';

3-1-7. ์ธ๋ฑ์Šค ๋จธ์ง€ - ํ•ฉ์ง‘ํ•ฉ(index_merge_union)

  • ์ธ๋ฑ์Šค ๋จธ์ง€์˜ 'Using union'์€ WHERE ์ ˆ์— ์‚ฌ์šฉ๋œ 2๊ฐœ ์ด์ƒ์˜ ์กฐ๊ฑด์ด ๊ฐ๊ฐ์˜ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋˜ OR ์—ฐ์‚ฐ์ž๋กœ ์—ฐ๊ฒฐ๋œ ๊ฒฝ์šฐ์— ์‚ฌ์šฉ๋˜๋Š” ์ตœ์ ํ™”๋‹ค.
  • ์˜ˆ์‹œ
    • first_name ์นผ๋Ÿผ์€ ix_firstname ์ธ๋ฑ์Šค
    • hire_date ์นผ๋Ÿผ์€ ix_hiredate ์ธ๋ฑ์Šค
mysql> EXPLAIN
       SELECT * FROM employees
       WHERE first_name='Matt' OR hire_date='1987-03-31';
+-------------+--------------------------+---------+------+----------------------------------------------------+
| type        | key                      | key_len | rows | Extra                                              |
+-------------+--------------------------+---------+------+----------------------------------------------------+
| index_merge | ix_firstname,ix_hiredate | 58,3    |  344 | Using union(ix_firstname,ix_hiredate); Using where |
+-------------+--------------------------+---------+------+----------------------------------------------------+
  • "Using union(ix_firstname,ix_hiredate)"์ด๋ผ๊ณ  ํ‘œ์‹œ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ธ๋ฑ์Šค ๋จธ์ง€ ์ตœ์ ํ™”๊ฐ€ ix_firstname๊ณผ ix_hiredate ์ธ๋ฑ์Šค ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ Union ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ๋ณ‘ํ•ฉํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธ์ด๋‹ค. (ํ•ฉ์ง‘ํ•ฉ)
  • MySQL ์„œ๋ฒ„๋Š” ๋‘ ๊ฐœ์˜ ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•œ ๊ฒฐ๊ณผ์˜ ์ง‘ํ•ฉ์„ ์ •๋ ฌํ•ด ์ค‘๋ณต ๋ ˆ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • ๋‘ ๊ฐœ์˜ ์ง‘ํ•ฉ์€ ํ”„๋ผ์ด๋จธ๋ฆฌํ‚ค(emp_no)๋กœ ์ •๋ ฌ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค๋กœ ์ •๋ ฌํ•˜์—ฌ emp_no ์นผ๋Ÿผ์ด ์ค‘๋ณต๋œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ํ•˜๋‚˜์˜ ๋ ˆ์ฝ”๋“œ๋งŒ ๋‚ด๋ณด๋‚ธ๋‹ค.
  • ์ค‘๋ณต ์ œ๊ฑฐ๋ฅผ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์šฐ์„ ์ˆœ์œ„ ํ(Priority Queue)์ด๋‹ค.

์ฃผ์˜

  • ์‚ฌ์‹ค SQL ๋ฌธ์žฅ์—์„œ AND ์—ฐ์‚ฐ์ž์™€ OR ์—ฐ์‚ฐ์ž๋Š” ์ƒ๋‹นํžˆ ํฐ ์ฐจ์ด๋ฅผ ๋ณด์ธ๋‹ค. 2๊ฐœ์˜ ์กฐ๊ฑด์ด AND๋กœ ์—ฐ๊ฒฐ๋œ ๊ฒฝ์šฐ์—๋Š” ๋‘ ์กฐ๊ฑด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ์ธ๋ฑ์Šค ๋ ˆ์ธ์ง€ ์Šค์บ”์œผ๋กœ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
  • ํ•˜์ง€๋งŒ 2๊ฐœ์˜ WHERE ์กฐ๊ฑด์ด OR ์—ฐ์‚ฐ์ž๋กœ ์—ฐ๊ฒฐ๋œ ๊ฒฝ์šฐ์—๋Š” ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ œ๋Œ€๋กœ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋ฉด ํ•ญ์ƒ ํ’€ ํ…Œ์ด๋ธ” ์Šค์บ”์œผ๋กœ๋ฐ–์— ์ฒ˜๋ฆฌํ•˜์ง€ ๋ชปํ•œ๋‹ค.

3-1-8. ์ธ๋ฑ์Šค ๋จธ์ง€ - ์ •๋ ฌ ํ›„ ํ•ฉ์ง‘ํ•ฉ(index_merge_sort_union)

  • ๋งŒ์•ฝ ์ธ๋ฑ์Šค ๋จธ์ง€ ์ž‘์—…์„ ํ•˜๋Š” ๋„์ค‘์— ๊ฒฐ๊ณผ์˜ ์ •๋ ฌ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ MySQL ์„œ๋ฒ„๋Š” ์ธ๋ฑ์Šค ๋จธ์ง€ ์ตœ์ ํ™”์˜ 'Sort Union' ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•œ๋‹ค.
mysql> EXPLAIN 
       SELECT * FROM employees 
       WHERE first_name='Matt' 
          OR hire_date BETWEEN '1987-03-01' AND '1987-03-31';
+-------------+--------------------------+---------+------+---------------------------------------------------------+
| type        | key                      | key_len | rows | Extra                                                   |
+-------------+--------------------------+---------+------+---------------------------------------------------------+
| index_merge | ix_firstname,ix_hiredate | 58,3    | 3197 | Using sort_union(ix_firstname,ix_hiredate); Using where |
+-------------+--------------------------+---------+------+---------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
  • ์œ„์˜ ์˜ˆ์ œ๋ฅผ Union ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์„ค๋ช…๊ณผ ๊ฐ™์ด 2๊ฐœ์˜ ์ฟผ๋ฆฌ๋กœ ๋ถ„๋ฆฌํ•ด ์ƒ๊ฐํ•ด๋ณด์ž.
mysql> SELECT * FROM employees WHERE first_name='Matt';
mysql> SELECT * FROM employees WHERE hire_date BETWEEN '1987-03-01' AND '1987-03-31';
  • first_name='Matt' ์ ˆ์€ emp_no๋กœ ์ •๋ ฌ๋˜์–ด ์ถœ๋ ฅ๋˜์ง€๋งŒ hire_date BETWEEN '1987-03-01' AND '1987-03-31' ์กฐ๊ฑด์€ ix_hiredate index ์ˆœ์„œ๋Œ€๋กœ ์ •๋ ฌ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— emp_no ์นผ๋Ÿผ์œผ๋กœ ์ •๋ ฌ๋˜์ง€ ์•Š๋Š”๋‹ค.
    • ์ฆ‰, ์œ„ ์˜ˆ์ œ์˜ ๊ฒฐ๊ณผ์—์„œ๋Š” ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด ์šฐ์„ ์ˆœ์œ„ ํ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
    • ๊ทธ๋ž˜์„œ MySQL ์„œ๋ฒ„๋Š” ๋‘ ์ง‘ํ•ฉ์˜ ๊ฒฐ๊ณผ์—์„œ ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ ์ง‘ํ•ฉ์„ emp_no ์นผ๋Ÿผ์œผ๋กœ ์ •๋ ฌํ•œ ๋‹ค์Œ ์ค‘๋ณต ์ œ๊ฑฐ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

์„ธ๋ฏธ ์กฐ์ธ(semijoin)

  • ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”๊ณผ ์‹ค์ œ ์กฐ์ธ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ณ  ๋‹จ์ง€ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ ์กฐ๊ฑด์— ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๊ฐ€ ์žˆ๋Š”์ง€ ์—†๋Š”์ง€๋งŒ ์ฒดํฌํ•˜๋Š” ํ˜•ํƒœ์˜ ์ฟผ๋ฆฌ๋ฅผ ์„ธ๋ฏธ ์กฐ์ธ์ด๋ผ๊ณ  ํ•œ๋‹ค.
  • MySQL 5.7 ๋ฒ„์ „์€ ์„ธ๋ฏธ ์กฐ์ธ ํ˜•ํƒœ์˜ ์ฟผ๋ฆฌ๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ๋ถ€๋ถ„์ด ์ƒ๋‹นํžˆ ์ทจ์•ฝํ–ˆ๋‹ค๊ณ  ํ•œ๋‹ค.
  • ์„ธ๋ฏธ์กฐ์ธ์ด ์ผœ์ ธ์žˆ์„ ๋• 57๊ฑด๋งŒ ์กฐํšŒํ•œ๋‹ค.
mysql> EXPLAIN SELECT * FROM employees e WHERE e.emp_no IN (SELECT de.emp_no FROM dept_emp de WHERE de.from_date='1995-01-01');
+----+--------------+-------------+------------+--------+-------------------------------+-------------+---------+--------------------+------+----------+-------------+
| id | select_type  | table       | partitions | type   | possible_keys                 | key         | key_len | ref                | rows | filtered | Extra       |
+----+--------------+-------------+------------+--------+-------------------------------+-------------+---------+--------------------+------+----------+-------------+
|  1 | SIMPLE       | <subquery2> | NULL       | ALL    | NULL                          | NULL        | NULL    | NULL               | NULL |   100.00 | NULL        |
|  1 | SIMPLE       | e           | NULL       | eq_ref | PRIMARY                       | PRIMARY     | 4       | <subquery2>.emp_no |    1 |   100.00 | NULL        |
|  2 | MATERIALIZED | de          | NULL       | ref    | ix_fromdate,ix_empno_fromdate | ix_fromdate | 3       | const              |   57 |   100.00 | Using index |
+----+--------------+-------------+------------+--------+-------------------------------+-------------+---------+--------------------+------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)
  • ๋ฐ˜๋ฉด ์„ธ๋ฏธ์กฐ์ธ์„ ๋„๊ณ  ์‹คํ–‰ํ•˜๋ฉด ๋ฌด๋ ค 30๋งŒ ๊ฑด ์ด์ƒ ์ฝ๊ณ  ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ์„ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ๋‹ค.
mysql> SET SESSION optimizer_switch='semijoin=off';
Query OK, 0 rows affected (0.00 sec)
    
mysql> EXPLAIN SELECT * FROM employees e WHERE e.emp_no IN (SELECT de.emp_no FROM dept_emp de WHERE de.from_date='1995-01-01');
+----+-------------+-------+------------+------+-------------------------------+-------------+---------+-------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys                 | key         | key_len | ref   | rows   | filtered | Extra       |
+----+-------------+-------+------------+------+-------------------------------+-------------+---------+-------+--------+----------+-------------+
|  1 | PRIMARY     | e     | NULL       | ALL  | NULL                          | NULL        | NULL    | NULL  | 300141 |   100.00 | Using where |
|  2 | SUBQUERY    | de    | NULL       | ref  | ix_fromdate,ix_empno_fromdate | ix_fromdate | 3       | const |     57 |   100.00 | Using index |
+----+-------------+-------+------------+------+-------------------------------+-------------+---------+-------+--------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
  • ์„ธ๋ฏธ ์กฐ์ธ ํ˜•ํƒœ์˜ ์ฟผ๋ฆฌ์™€ ์•ˆํ‹ฐ ์„ธ๋ฏธ ์กฐ์ธ ํ˜•ํƒœ์˜ ์ฟผ๋ฆฌ๋Š” ์ตœ์ ํ™” ๋ฐฉ๋ฒ•์ด ์กฐ๊ธˆ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.
  • ์„ธ๋ฏธ ์กฐ์ธ ํ˜•ํƒœ๋Š” 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์„ธ๋ฏธ ์กฐ์ธ ์ตœ์ ํ™”
    • IN-to-EXISTS ์ตœ์ ํ™”
    • MATERIALIZATION ์ตœ์ ํ™”
  • ์•ˆํ‹ฐ ์„ธ๋ฏธ ์กฐ์ธ ํ˜•ํƒœ๋Š” 2๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.
    • IN-to-EXISTS ์ตœ์ ํ™”
    • MATERIALIZATION ์ตœ์ ํ™”
  • ์ตœ๊ทผ ๋„์ž…๋œ ์„ธ๋ฏธ ์กฐ์ธ ์ตœ์ ํ™”๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์ตœ์ ํ™” ์ „๋žต์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
    • Table Pull-out
    • Duplicate Weed-out
    • First Match
    • Loose Scan
    • Materialization

ํ…Œ์ด๋ธ” ํ’€-์•„์›ƒ (Table Pull-out)

  • ์„ธ๋ฏธ ์กฐ์ธ์˜ ์„œ๋ธŒ์ฟผ๋ฆฌ์— ์‚ฌ์šฉ๋œ ํ…Œ์ด๋ธ”์„ ์•„์šฐํ„ฐ ์ฟผ๋ฆฌ๋กœ ๋„์ง‘์–ด๋‚ธ ํ›„ ์ฟผ๋ฆฌ๋ฅผ ์กฐ์ธ ์ฟผ๋ฆฌ๋กœ ์žฌ์ž‘์„ฑํ•˜๋Š” ํ˜•ํƒœ์˜ ์ตœ์ ํ™”๋‹ค.
  • ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ์ตœ์ ํ™”๊ฐ€ ๋„์ž…๋˜๊ธฐ ์ „ ์ˆ˜๋™์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ํŠœ๋‹ํ•˜๋˜ ๋Œ€ํ‘œ์ ์ธ ๋ฐฉ๋ฒ•์ด์—ˆ๋‹ค.
mysql> EXPLAIN
    -> SELECT * FROM employees e
    -> WHERE e.emp_no IN (SELECT de.emp_no FROM dept_emp de WHERE de.dept_no='d009');
+----+-------------+-------+------------+--------+---------------------------+---------+---------+---------------------+-------+----------+-------------+
| id | select_type | table | partitions | type   | possible_keys             | key     | key_len | ref                 | rows  | filtered | Extra       |
+----+-------------+-------+------------+--------+---------------------------+---------+---------+---------------------+-------+----------+-------------+
|  1 | SIMPLE      | de    | NULL       | ref    | PRIMARY,ix_empno_fromdate | PRIMARY | 16      | const               | 46012 |   100.00 | Using index |
|  1 | SIMPLE      | e     | NULL       | eq_ref | PRIMARY                   | PRIMARY | 4       | employees.de.emp_no |     1 |   100.00 | NULL        |
+----+-------------+-------+------------+--------+---------------------------+---------+---------+---------------------+-------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
  • ํ…Œ์ด๋ธ” ํ’€์•„์›ƒ ์ตœ์ ํ™”๋Š” ๋ณ„๋„์˜ ์‹คํ–‰ ๊ณ„ํš์˜ Extra ์นผ๋Ÿผ์— "Using table pullout"๊ณผ ๊ฐ™์€ ๋ฌธ๊ตฌ๊ฐ€ ์ถœ๋ ฅ๋˜์ง€ ์•Š๋Š”๋‹ค. ์ตœ์ ํ™”๊ฐ€ ์‚ฌ์šฉ๋๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ํ•ด๋‹น ํ…Œ์ด๋ธ”๋“ค์˜ id ์นผ๋Ÿผ๊ฐ’์ด ๊ฐ™์€์ง€ ๋‹ค๋ฅธ์ง€ ๋น„๊ตํ•ด๋ณด๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๋‹ค.
  • ์œ„์˜ ์˜ˆ์‹œ์—์„œ๋Š” id ์นผ๋Ÿผ ๊ฐ’์ด ๋ชจ๋‘ 1๋กœ ํ‘œ์‹œ๋˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์•„ ํ…Œ์ด๋ธ” ํ’€์•„์›ƒ ์ตœ์ ํ™”๊ฐ€ ์ง„ํ–‰๋œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
mysql> SHOW WARNINGS;
Level: Note
Code: 1003
Message:  /* select#1 */
    select `employees`.`e`.`emp_no` AS `emp_no`,
       `employees`.`e`.`birth_date` AS `birth_date`,
       `employees`.`e`.`first_name` AS `first_name`,
       `employees`.`e`.`last_name` AS `last_name`,
       `employees`.`e`.`gender` AS `gender`,
       `employees`.`e`.`hire_date` AS `hire_date` 
    from `employees`.`dept_emp` `de` 
        join `employees`.`employees` `e` 
    where ((`employees`.`e`.`emp_no` = `employees`.`de`.`emp_no`) 
               and (`employees`.`de`.`dept_no` = 'd009')) 
1 row in set (0.00 sec)
  • SHOW WARNINGS ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์ฟผ๋ฆฌ๊ฐ€ ์–ด๋–ค ์‹์œผ๋กœ ์žฌ์ž‘์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•ด๋‹น ์ฟผ๋ฆฌ๋ฅผ ํ™•์บํ•ด๋ณด๋ฉด IN(subquery) ํ˜•ํƒœ๋Š” ์‚ฌ๋ผ์ง€๊ณ  JOIN์œผ๋กœ ์ฟผ๋ฆฌ๊ฐ€ ์žฌ์ž‘์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ…Œ์ด๋ธ” ํ’€์•„์›ƒ์˜ ํŠน์„ฑ์„ ์ •๋ฆฌํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
    • ์„ธ๋ฏธ ์กฐ์ธ ์„œ๋ธŒ์ฟผ๋ฆฌ์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
    • ์„œ๋ธŒ์ฟผ๋ฆฌ ๋ถ€๋ถ„์ด UNIQUE ์ธ๋ฑ์Šค๋‚˜ ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค ๋ฃฉ์—…์œผ๋กœ ๊ฒฐ๊ณผ๊ฐ€ 1๊ฑด์ธ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
    • ์ ์šฉ๋œ๋‹ค ํ•˜๋”๋ผ๋„ ๊ธฐ๋ณธ ์ฟผ๋ฆฌ์—์„œ ๊ฐ€๋Šฅํ–ˆ๋˜ ์ตœ์ ํ™” ๋ฐฉ๋ฒ•์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๋ฏ€๋กœ MySQL์—์„œ๋Š” ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ํ…Œ์ด๋ธ” ํ’€์•„์›ƒ์„ ์ตœ๋Œ€ํ•œ ์ ์šฉํ•œ๋‹ค.
    • ํ…Œ์ด๋ธ” ํ’€์•„์›ƒ ์ตœ์ ํ™”๋Š” ์„œ๋ธŒ์ฟผ๋ฆฌ์˜ ํ…Œ์ด๋ธ”์„ ์•„์šฐํ„ฐ ์ฟผ๋ฆฌ๋กœ ๊ฐ€์ ธ์™€์„œ ์กฐ์ธ์œผ๋กœ ํ’€์–ด์“ฐ๋Š” ์ตœ์ ํ™”๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ ๋งŒ์•ฝ ์„œ๋ธŒ์ฟผ๋ฆฌ์˜ ๋ชจ๋“  ํ…Œ์ด๋ธ”์ด ์•„์šฐํ„ฐ ์ฟผ๋ฆฌ๋กœ ๋„์ง‘์–ด๋‚ผ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์„œ๋ธŒ์ฟผ๋ฆฌ ์ž์ฒด๋Š” ์—†์–ด์ง„๋‹ค.
    • MySQL์—์„œ๋Š” "์ตœ๋Œ€ํ•œ ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ์กฐ์ธ์œผ๋กœ ํ’€์–ด์„œ ์‚ฌ์šฉํ•ด๋ผ"๋ผ๋Š” ํŠœ๋‹ ๊ฐ€์ด๋“œ๊ฐ€ ๋งŽ์€๋ฐ ํ…Œ์ด๋ธ” ํ’€์•„์›ƒ ์ตœ์ ํ™”๋Š” ์‚ฌ์‹ค ์ด ๊ฐ€์ด๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

ํผ์ŠคํŠธ ๋งค์น˜ (firstmatch)

  • ํผ์ŠคํŠธ ๋งค์น˜ ์ „๋žต์€ IN(subquery) ํ˜•ํƒœ์˜ ์„ธ๋ฏธ ์กฐ์ธ์„ EXIST(subquery) ํ˜•ํƒœ๋กœ ํŠœ๋‹ํ•œ ๊ฒƒ๊ณผ ๋น„์Šทํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.
  • ์‹คํ–‰ ๊ณ„ํš์„ ๋ณด๋ฉด Extra ์นผ๋Ÿผ์— FirstMatch(e)๋ผ๋Š” ๋ฌธ๊ตฌ๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.
mysql> EXPLAIN 
    SELECT * FROM employees e 
    WHERE e.emp_no IN 
          (SELECT de.emp_no FROM dept_emp de WHERE de.dept_no='d009');
+----+-------------+-------+------------+--------+---------------------------+---------+---------+---------------------+-------+----------+-------------+
| id | select_type | table | partitions | type   | possible_keys             | key     | key_len | ref                 | rows  | filtered | Extra       |
+----+-------------+-------+------------+--------+---------------------------+---------+---------+---------------------+-------+----------+-------------+
|  1 | SIMPLE      | de    | NULL       | ref    | PRIMARY,ix_empno_fromdate | PRIMARY | 16      | const               | 46012 |   100.00 | Using index |
|  1 | SIMPLE      | e     | NULL       | eq_ref | PRIMARY                   | PRIMARY | 4       | employees.de.emp_no |     1 |   100.00 | NULL        |
+----+-------------+-------+------------+--------+---------------------------+---------+---------+---------------------+-------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
  • ํผ์ŠคํŠธ๋งค์น˜๋Š” ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋ผ ์กฐ์ธ์œผ๋กœ ํ’€์–ด ์‹คํ–‰ํ•˜๋ฉด์„œ ์ผ์น˜ํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ๋ ˆ์ฝ”๋“œ๋งŒ ๊ฒ€์ƒ‰ํ•˜๋Š” ์ตœ์ ํ™”๋ฅผ ์‹คํ–‰ํ•œ ๊ฒƒ์ด๋‹ค.
  • ์˜ˆ์‹œ์—์„œ๋Š” titles ํ…Œ์ด๋ธ”์— ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ 1๊ฑด๋งŒ ์ฐพ์œผ๋ฉด ๋”์ด์ƒ titles ํ…Œ์ด๋ธ” ๊ฒ€์ƒ‰์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

  • ํผ์ŠคํŠธ ๋งค์น˜ ์ตœ์ ํ™”์˜ ํŠน์„ฑ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
    • ์„œ๋ธŒ์ฟผ๋ฆฌ์—์„œ ํ•˜๋‚˜์˜ ๋ ˆ์ฝ”๋“œ๋งŒ ๊ฒ€์ƒ‰๋˜๋ฉด ๋”์ด์ƒ์˜ ๊ฒ€์ƒ‰์„ ๋ฉˆ์ถ”๋Š” ๋‹จ์ถ• ์‹คํ–‰ ๊ฒฝ๋กœ(Short-cut path)์ด๊ธฐ ๋•Œ๋ฌธ์— ํผ์ŠคํŠธ๋งค์น˜ ์ตœ์ ํ™”์—์„œ ์„œ๋ธŒ์ฟผ๋ฆฌ๋Š” ๊ทธ ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ์ฐธ์กฐํ•˜๋Š” ๋ชจ๋“  ์•„์šฐํ„ฐ ํ…Œ์ด๋ธ”์ด ๋จผ์ € ์กฐํšŒ๋œ ์ดํ›„์— ์‹คํ–‰๋œ๋‹ค.
    • ์‹คํ–‰ ๊ณ„ํš์˜ Extra ์นผ๋Ÿผ์—์„œ FirstMatch(table-N) ๋ฌธ๊ตฌ๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.
    • ์ƒ๊ด€ ์„œ๋ธŒ์ฟผ๋ฆฌ(Correlated subquery)์—์„œ๋„ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค.
    • GROUP BY๋‚˜ ์ง‘ํ•ฉ ํ•จ์ˆ˜๊ฐ€ ์‚ฌ์šฉ๋œ ์„œ๋ธŒ์ฟผ๋ฆฌ์˜ ์ตœ์ ํ™”์—๋Š” ์‚ฌ์šฉ๋  ์ˆ˜ ์—†๋‹ค.

๋ฃจ์Šค ์Šค์บ”(loosescan)

  • GROUP BY ์ตœ์ ํ™”์—์„œ ์‚ดํŽด๋ณธ "Using index for group-by"์˜ ๋ฃจ์Šค ์ธ๋ฑ์Šค ์Šค์บ”(Loose Index Scan)๊ณผ ๋น„์Šทํ•œ ์ฝ๊ธฐ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.
mysql> EXPLAIN
    -> SELECT * FROM departments d 
    -> WHERE d.dept_no IN(SELECT de.dept_no FROM dept_emp de);
+----+-------------+-------+------------+-------+---------------+---------+---------+------+--------+----------+--------------------------------------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows   | filtered | Extra                                      |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+--------+----------+--------------------------------------------+
|  1 | SIMPLE      | de    | NULL       | index | PRIMARY       | PRIMARY | 20      | NULL | 331143 |     0.00 | Using index; LooseScan                     |
|  1 | SIMPLE      | d     | NULL       | ALL   | PRIMARY       | NULL    | NULL    | NULL |      9 |    11.11 | Using where; Using join buffer (hash join) |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+--------+----------+--------------------------------------------+
2 rows in set, 1 warning (0.00 sec)
  • departments ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๋Š” 9๊ฑด๋ฐ–์— ๋˜์ง€ ์•Š์ง€๋งŒ dept_emp ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ ๊ฑด์ˆ˜๋Š” ๋ฌด๋ ค 33๋งŒ ๊ฑด ๊ฐ€๊นŒ์ด ์ €์žฅ๋˜์–ด ์žˆ๋‹ค.
  • dept_emp ํ…Œ์ด๋ธ”์—๋Š” (dept_no, emp_no) ์กฐํ•ฉ์˜ ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค ์ธ๋ฑ์Šค๊ฐ€ ๋งŒ๋“ค์–ด์ ธ ์žˆ๋‹ค.dept_no๋งŒ์œผ๋กœ ๊ทธ๋ฃจํ•‘ํ•ด๋ณด๋ฉด ๊ฒฐ๊ตญ 9๊ฑด ๋ฐ–์— ์—†๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
  • dept_emp ํ…Œ์ด๋ธ”์˜ ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค๋ฅผ ๋ฃจ์Šค ์ธ๋ฑ์Šค ์Šค์บ”์œผ๋กœ ์œ ๋‹ˆํฌํ•œ dept_no๋งŒ ์ฝ์œผ๋ฉด ์ค‘๋ณต๋œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๋ฉด์„œ ์•„์ฃผ ํšจ์œจ์ ์œผ๋กœ ์„œ๋ธŒ์ฟผ๋ฆฌ ๋ถ€๋ถ„์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์„œ๋ธŒ์ฟผ๋ฆฌ์— ์‚ฌ์šฉ๋œ dept_emp ํ…Œ์ด๋ธ”์˜ ํ”„๋ผ์ด๋จธ๋ฆฌ ํ‚ค๋ฅผ dept_no ๋ถ€๋ถ„์—์„œ ์œ ๋‹ˆํฌํ•˜๊ฒŒ ํ•œ ๊ฑด์”ฉ๋งŒ ์ฝ๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ค€๋‹ค.

๊ตฌ์ฒดํ™” (Materialization)

  • ์„ธ๋ฏธ ์กฐ์ธ์— ์‚ฌ์šฉ๋œ ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ํ†ต์งธ๋กœ ๊ตฌ์ฒดํ™”ํ•ด์„œ ์ฟผ๋ฆฌ๋ฅผ ์ตœ์ ํ™”ํ•œ๋‹ค๋Š” ์˜๋ฏธ๋‹ค.
  • ์‰ฝ๊ฒŒ ํ‘œํ˜„ํ•˜๋ฉด ๋‚ด๋ถ€ ์ž„์‹œ ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
mysql> EXPLAIN
    -> SELECT *
    -> FROM employees e
    -> WHERE e.emp_no IN
    -> (SELECT de.emp_no FROM dept_emp de
    -> WHERE de.from_date='1995-01-01');
+----+--------------+-------------+------------+--------+-------------------------------+-------------+---------+--------------------+------+----------+-------------+
| id | select_type  | table       | partitions | type   | possible_keys                 | key         | key_len | ref                | rows | filtered | Extra       |
+----+--------------+-------------+------------+--------+-------------------------------+-------------+---------+--------------------+------+----------+-------------+
|  1 | SIMPLE       | <subquery2> | NULL       | ALL    | NULL                          | NULL        | NULL    | NULL               | NULL |   100.00 | NULL        |
|  1 | SIMPLE       | e           | NULL       | eq_ref | PRIMARY                       | PRIMARY     | 4       | <subquery2>.emp_no |    1 |   100.00 | NULL        |
|  2 | MATERIALIZED | de          | NULL       | ref    | ix_fromdate,ix_empno_fromdate | ix_fromdate | 3       | const              |   57 |   100.00 | Using index |
+----+--------------+-------------+------------+--------+-------------------------------+-------------+---------+--------------------+------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)
  • ํ•ด๋‹น ์ฟผ๋ฆฌ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ํ…Œ์ด๋ธ”์€ 2๊ฐœ์ธ๋ฐ ์‹คํ–‰ ๊ณ„ํš์€ 3๊ฐœ ๋ผ์ธ์ด ์ถœ๋ ฅ๋˜์—ˆ๋‹ค. ์‹คํ–‰ ๊ณ„ํš ์–ด๋””์„ ๊ฐ€ ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ์ƒ์„ฑ๋๋‹ค๋Š” ๊ฒƒ์„ ์ง์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • dept_emp ํ…Œ์ด๋ธ”์„ ์ฝ๋Š” ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ๋จผ์ € ์‹คํ–‰๋˜์–ด ๊ทธ ๊ฒฐ๊ณผ๋กœ ์ž„์‹œ ํ…Œ์ด๋ธ”()๊ฐ€ ๋งŒ๋“ค์–ด์กŒ๋‹ค. ์ตœ์ข…์ ์œผ๋กœ ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ๊ตฌ์ฒดํ™”๋œ ์ž„์‹œ ํ…Œ์ด๋ธ” ()๊ณผ employees ํ…Œ์ด๋ธ”์„ ์กฐ์ธํ•ด์„œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • Materialization๋Š” ๋‹ค๋ฅธ ์„œ๋ธŒ์ฟผ๋ฆฌ ์ตœ์ ํ™”์™€ ๋‹ค๋ฅด๊ฒŒ ์„œ๋ธŒ์ฟผ๋ฆฌ ๋‚ด์— GROUP BY ์ ˆ์ด ์žˆ์–ด๋„ ์ด ์ตœ์ ํ™” ์ „๋žต์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
mysql> EXPLAIN
    -> SELECT *
    -> FROM employees e
    -> WHERE e.emp_no IN
    -> (SELECT de.emp_no FROM dept_emp de
    -> WHERE de.from_date='1995-01-01'
    -> GROUP BY de.dept_no);
+----+--------------+-------------+------------+--------+-------------------------------+-------------+---------+--------------------+------+----------+-------------+
| id | select_type  | table       | partitions | type   | possible_keys                 | key         | key_len | ref                | rows | filtered | Extra       |
+----+--------------+-------------+------------+--------+-------------------------------+-------------+---------+--------------------+------+----------+-------------+
|  1 | SIMPLE       | <subquery2> | NULL       | ALL    | NULL                          | NULL        | NULL    | NULL               | NULL |   100.00 | NULL        |
|  1 | SIMPLE       | e           | NULL       | eq_ref | PRIMARY                       | PRIMARY     | 4       | <subquery2>.emp_no |    1 |   100.00 | NULL        |
|  2 | MATERIALIZED | de          | NULL       | ref    | ix_fromdate,ix_empno_fromdate | ix_fromdate | 3       | const              |   57 |   100.00 | Using index |
+----+--------------+-------------+------------+--------+-------------------------------+-------------+---------+--------------------+------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)
  • Materialization์˜ ํŠน์„ฑ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.
    • IN(subquery)์—์„œ ์„œ๋ธŒ์ฟผ๋ฆฌ๋Š” ์ƒ๊ด€ ์„œ๋ธŒ์ฟผ๋ฆฌ(Correlated subquery)๊ฐ€ ์•„๋‹ˆ์–ด์•ผ ํ•œ๋‹ค.
    • ์„œ๋ธŒ์ฟผ๋ฆฌ๋Š” GROUP BY๋‚˜ ์ง‘ํ•ฉ ํ•จ์ˆ˜๋“ค์ด ์‚ฌ์šฉ๋ผ๋„ ๊ตฌ์ฒดํ™”๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ๊ตฌ์ฒดํ™”๊ฐ€ ์‚ฌ์šฉ๋œ ๊ฒฝ์šฐ์—๋Š” ๋‚ด๋ถ€ ์ž„์‹œ ํ…Œ์ด๋ธ”์ด ์‚ฌ์šฉ๋œ๋‹ค.