DevLog ๐Ÿ˜ถ

[Real MySQL 8.0] InnoDB์˜ ์ธ๋ฑ์Šค์™€ ๋ฝ, ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€ ๋ณธ๋ฌธ

๐Ÿ“–/Real MySQL 8.0

[Real MySQL 8.0] InnoDB์˜ ์ธ๋ฑ์Šค์™€ ๋ฝ, ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€

dolmeng2 2023. 6. 19. 00:51

๐ŸŒฑ ๋“ค์–ด๊ฐ€๊ธฐ ์ „

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” InnoDB์˜ ์ธ๋ฑ์Šค์™€ ๋ฝ์˜ ์ƒ๊ด€๊ด€๊ณ„์™€ ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์ž.
 


 

๐ŸŒฑ ์ธ๋ฑ์Šค์™€ ๋ฝ

์ง€๋‚œ ํฌ์ŠคํŒ…์—์„œ ๋ ˆ์ฝ”๋“œ ๋ฝ์— ๋Œ€ํ•ด ์ •๋ฆฌํ•  ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ˜ํŠธ๋ฅผ ๋‚จ๊ฒผ๋‹ค.

innoDB์˜ ๊ฒฝ์šฐ ๋ ˆ์ฝ”๋“œ ์ž์ฒด๋ฅผ ์ž ๊ทธ๋Š” ๊ฒƒ๋ณด๋‹ค๋Š”, ์ธ๋ฑ์Šค์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ž ๊ทผ๋‹ค.

์ธ๋ฑ์Šค๋ฅผ ์ž ๊ทธ๊ธฐ ๋•Œ๋ฌธ์— ๋ ˆ์ฝ”๋“œ ๊ฒ€์ƒ‰ ์‹œ ๋ฐœ๊ฒฌ๋œ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ์˜ ๋ฝ์„ ๊ฑธ๊ฒŒ ๋œ๋‹ค.
 
์˜ˆ๋ฅผ ๋“ค์–ด, crew ํ…Œ์ด๋ธ”์— age = 23์ธ ์‚ฌ๋žŒ์ด 100๋ช…์ด๋ผ๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž.
์ด๋•Œ, age์—๋Š” ์ธ๋ฑ์Šค๊ฐ€, name์—๋Š” ์ธ๋ฑ์Šค๊ฐ€ ๊ฑธ๋ ค์žˆ์ง€ ์•Š์€ ์ƒํƒœ๋‹ค.

SELECT COUNT(*) FROM crew WHERE age = 23;
# result: 100

 
ํ•˜์ง€๋งŒ, age = 23์ด๋ฉด์„œ name = 'journey'์ธ ๊ฒฐ๊ณผ๋Š” 1๊ฐœ๋งŒ ๋‚˜์˜จ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

SELECT COUNT(*) FROM crew WHERE age = 23 and name = 'journey';
# result: 1

 
์ด๋•Œ, age = 23์ด๊ณ  name = 'journey'์ธ ๋ ˆ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ last_modified_at ๋ ˆ์ฝ”๋“œ๋ฅผ NOW()๋กœ ์—…๋ฐ์ดํŠธํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž.

UPDATE crew SET last_modified_at = NOW() WHERE age = 23 and name = 'journey';

 
์œ„์˜ ์ฟผ๋ฆฌ๋ฌธ์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ช‡ ๊ฐœ์˜ ๋ ˆ์ฝ”๋“œ์— ๋ฝ์„ ๊ฑธ๊ฒŒ ๋ ๊นŒ?

๋ฐ”๋กœ, age = 23์˜ ๊ฒฐ๊ณผ๋กœ ๋‚˜์˜จ 100๊ฐœ์˜ ๋ ˆ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ ๋ชจ๋‘ ๋ฝ์ด ๊ฑธ๋ฆฌ๊ฒŒ ๋œ๋‹ค.
์ธ๋ฑ์Šค๊ฐ€ ๋งŒ์•ฝ ํ•˜๋‚˜๋„ ์—†๋‹ค๋ฉด ํ…Œ์ด๋ธ”์— ๋Œ€ํ•ด ์ „์ฒด ์Šค์บ” (full-scan)์„ ํ•˜๋ฉด์„œ update๋ฅผ ์ง„ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ ๋ฝ์„ ๊ฑธ๊ฒŒ ๋  ๊ฒƒ์ด๊ณ , ์„ฑ๋Šฅ์— ์น˜๋ช…์ ์ธ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ธ๋ฑ์Šค๋ฅผ ์ž˜ ๊ฑฐ๋Š” ๊ฒƒ์ด ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค!
 
MySQL 8.0๋ถ€ํ„ฐ๋Š” ๋ฝ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ performance_schema DB๋ฅผ ํ†ตํ•ด์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

SELECT
    t1.trx_id waiting_trx_id,
    t1.trx_mysql_thread_id waiting_thread,
    t1.trx_query waiting_query,
    t2.trx_id blocking_trx_id,
    t2.trx_mysql_thread_id blocking_thread,
    t2.trx_query blocking_query
FROM performance_schema.data_lock_waits w
INNER JOIN information_schema.INNODB_TRX t1 ON t1.trx_id = w.REQUESTING_ENGINE_TRANSACTION_ID
INNER JOIN information_schema.INNODB_TRX t2 ON t2.trx_id = w.BLOCKING_ENGINE_TRANSACTION_ID

waiting_trx_id์˜ ๊ฒฝ์šฐ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” ํŠธ๋žœ์žญ์…˜์˜ ์•„์ด๋””๋ฅผ, waiting_thread๋Š” ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” ์Šค๋ ˆ๋“œ์˜ ๋ฒˆํ˜ธ๋ฅผ, waiting_query๋Š” ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋Š” ์ฟผ๋ฆฌ ์ •๋ณด๋ฅผ, blocking_trx_id๋Š” ๋ธ”๋ฝํ‚น ์ƒํƒœ์— ์žˆ๋Š” ํŠธ๋žœ์žญ์…˜์˜ ์•„์ด๋””๋ฅผ, blocking_thread๋Š” ๋ธ”๋ฝํ‚น ์ƒํƒœ์— ์žˆ๋Š” ์Šค๋ ˆ๋“œ๋ฅผ, blocking_query๋Š” ๋ธ”๋ฝํ‚น ์ƒํƒœ์— ์žˆ๋Š” ์ฟผ๋ฆฌ ์ •๋ณด๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
 
์—ฌ๊ธฐ์„œ ๋Œ€๊ธฐ ์ƒํƒœ๋Š” ํŠธ๋žœ์žญ์…˜์ด ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์˜ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ƒํƒœ๋ฅผ, ๋ธ”๋ฝํ‚น ์ƒํƒœ๋Š” ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ์ด๋ฏธ ์‚ฌ์šฉ ์ค‘์ธ ๋ฐ์ดํ„ฐ๋‚˜ ๋ฝ์„ ์š”์ฒญํ•œ ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
= ์ฆ‰, waiting_trx_id๊ฐ€ blocking_trx_id๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋Š” ์ƒํƒœ๋ฅผ ํ•œ๋ˆˆ์— ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
๋ฝ์„ ํ’€๊ธฐ ์œ„ํ•ด์„œ๋Š” blocking_trx_id๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฝ์„ ํ•ด์ œํ•˜๊ณ , ๊ทธ ๋’ค๋กœ waiting_trx_id์˜ ์ž‘์—…์ด ์ด๋ฃจ์–ด์ ธ์•ผ ํ•œ๋‹ค.
 
๋งŒ์•ฝ ๋” ์ƒ์„ธํ•œ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด data_locks์˜ ํ…Œ์ด๋ธ”์„ ๋ชจ๋‘ ํ™•์ธํ•ด๋ณด์ž.

SELECT * FROM performance_schema.data_locks;

์—ฌ๊ธฐ์„œ engine_transaction_id์™€ thread_id, ๊ทธ๋ฆฌ๊ณ  lock_type๊ณผ lock_mode์„ ํ™•์ธํ•ด๋ณด๋ฉด ์–ด๋–ค ํŠธ๋žœ์žญ์…˜์ด ์–ด๋–ค ์Šค๋ ˆ๋“œ๊ฐ€ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ณ , ์–ด๋–ค ๋ฝ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€๊นŒ์ง€ ํ™•์ธ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๋งŒ์•ฝ ๊ฒฐ๊ณผ์—์„œ REC_NOT_GAP ์ด๋ผ๋Š” lock_mode๊ฐ€ ์žˆ๋‹ค๋ฉด ์ด๋Š” ๋ ˆ์ฝ”๋“œ ๋ฝ์—์„œ ๊ฐญ์ด ํฌํ•จ๋˜์ง€ ์•Š์€ ์ˆœ์ˆ˜ํ•œ ๋ฝ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค. (lock_mode์˜ ๊ฒฐ๊ณผ๋กœ๋Š” S[,GAP], X[,GAP], IS[,GAP], IX[,GAP], AUTO_INC ๋ฐ UNKNOWN๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค.)
 
๋งŒ์•ฝ, ํŠน์ • ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฝ์„ ๋„ˆ๋ฌด ์˜ค๋ž˜ ๋ณด์œ ํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด KILL์„ ํ•ด์ฃผ์ž.

KILL thread_id

 


 

๐ŸŒฑ ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€

ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์€ ์—ฌ๋Ÿฌ ํŠธ๋žœ์žญ์…˜์ด ๋™์‹œ์— ์ฒ˜๋ฆฌ๋  ๋•Œ ํŠน์ • ํŠธ๋žœ์žญ์…˜์ด ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์—์„œ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ์กฐํšŒํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ํ• ์ง€ ๋ง์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ํฌ๊ฒŒ 4๊ฐ€์ง€์˜ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์ด ์กด์žฌํ•˜๋ฉฐ, READ UNCOMMITTED / READ COMMITTED / REPEATABLE READ / SERIALIZABLE๋กœ ๋‚˜๋‰œ๋‹ค. Read Uncommitted์™€ Serializable์˜ ๊ฒฝ์šฐ ๋ณดํ†ต ์ž˜ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.
 

 DIRTY-READNON-REPEATABLE READPHANTOM READ
READ UNCOMMITTEDOOO
READ COMMITTEDXOO
REPEATABLE READXXO
(innoDB์—์„œ๋Š” ๋ฐœ์ƒ X)
SERIALIZABLEXXX

์˜ค๋ผํด์—์„œ๋Š” Read Committed๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, MySQL์—์„œ๋Š” Repeatable Read๋ฅผ ์ฃผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.
 


 

๐Ÿ’ฌ READ UNCOMMITTED

๊ธฐ๋ณธ์ ์œผ๋กœ ์ปค๋ฐ‹์ด๋‚˜ ๋กค๋ฐฑ ์—ฌ๋ถ€์— ์ƒ๊ด€์—†์ด ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์ด๋‹ค.
 

์œ„ ๊ทธ๋ฆผ์„ ๋ณด๋ฉด, ์•„์ง 'journey'๋ผ๋Š” ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ปค๋ฐ‹๋˜์ง€ ์•Š์•˜๋Š”๋ฐ๋„ ์‚ฌ์šฉ์ž B๊ฐ€ ํ•ด๋‹น ๋‚ด์šฉ์„ read ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
 
์ž‘์—…์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์•˜๋Š”๋ฐ๋„ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋Š” ํ˜„์ƒ์„ 'Dirty Read'๋ผ๊ณ  ํ•˜๋ฉฐ, ์ด๋Ÿฐ ๊ฒฝ์šฐ์—” ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚˜ํƒ€๋‚ฌ๋‹ค๊ฐ€ ์‚ฌ๋ผ์กŒ๋‹ค๊ฐ€ ํ•˜๋Š” ํ˜„์ƒ์„ ์ดˆ๋ž˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ์˜ ์ •ํ•ฉ์„ฑ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์›ฌ๋งŒํ•˜๋ฉด read uncommitted์˜ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
 


 

๐Ÿ’ฌ READ COMMITTED

์˜ค๋ผํด์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์ด๋ฉฐ, Dirty Read๊ฐ€ ํ•ด๊ฒฐ๋œ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์ด๋‹ค.
๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์— ์˜ํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„ Commit์ด ์™„๋ฃŒ๋œ ๋ฐ์ดํ„ฐ๋งŒ ์กฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.
 

์œ„ ๊ทธ๋ฆผ์„ ๋ณด๋ฉด, ๊ธฐ์กด์˜ 1๋ฒˆ ๋ ˆ์ฝ”๋“œ๋Š” name = hello์˜€๊ณ , ์ด์— ๋Œ€ํ•ด์„œ 'hi'๋ผ๊ณ  ์—…๋ฐ์ดํŠธ๋ฅผ ํ•œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
์ด๋•Œ ์‚ฌ์šฉ์ž B๊ฐ€ 1๋ฒˆ ๋ ˆ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ ์กฐํšŒํ•  ๋•Œ, ํ…Œ์ด๋ธ”์ด ์•„๋‹Œ ์—…๋ฐ์ดํŠธ ์‹œ ์–ธ๋‘ ๋กœ๊ทธ์— ์ €์žฅํ–ˆ๋˜ ๊ฐ’์„ ์ฝ์–ด์„œ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—…๋ฐ์ดํŠธ ๋˜๊ธฐ ์ „ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜๋˜๋ฉฐ, ์ถ”ํ›„ ์ปค๋ฐ‹์ด ๋˜์–ด์•ผ ์™„์ „ํ•˜๊ฒŒ ๋ฐ˜์˜์ด ์™„๋ฃŒ๋œ๋‹ค.
 

์ปค๋ฐ‹๋œ ๋ฐ์ดํ„ฐ๋งŒ ์ฝ๊ธฐ ๋•Œ๋ฌธ์— '์ž‘์—…์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š”๋‹ค'๋Š” Dirty Read๋Š” ํ•ด๊ฒฐ๋˜์—ˆ์ง€๋งŒ, ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์—์„œ SELECT ์‹œ ํ•ญ์ƒ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ UPDATE ์ด์ „์˜ ๋ฐ์ดํ„ฐ์™€ ์ดํ›„์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜๋˜๊ธฐ ๋•Œ๋ฌธ์— 'Non-Repeatable Read'๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
 
๋‹จ์ˆœํ•œ ์›น ์„œ๋น„์Šค์—์„œ ์ด๋Š” ํฌ๊ฒŒ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์ง€๋งŒ, ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์—์„œ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์ฝ๊ณ  ์“ฐ๋Š” ์ž‘์—…์ด ๊ธˆ์ „ ํ–‰์œ„์™€ ๊ด€๋ จ์ด ๋˜๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ํŠนํžˆ, ์ž…-์ถœ๊ธˆ ๋กœ์ง์„ ์ƒ๊ฐํ•ด๋ณด์ž. ์ฒ˜์Œ์— 10000์›์ด ์กฐํšŒ๋˜์–ด์„œ 1000์›์„ ์ถ”๊ฐ€ํ•˜๊ณ  11000์›์ด ๋‚˜์˜ค๊ธธ ๊ธฐ๋Œ€ํ–ˆ๋Š”๋ฐ, ๋‹ค์‹œ ์กฐํšŒํ•˜๋‹ˆ 6000์›์œผ๋กœ ๋‚˜์˜จ๋‹ค๋ฉด ๋งค์šฐ ๋‹นํ˜น์Šค๋Ÿฌ์šธ ๊ฒƒ์ด๋‹ค. 
 
์ฐธ๊ณ ๋กœ, ํŠธ๋žœ์žญ์…˜ ๋‚ด๋ถ€์—์„œ ์‹คํ–‰๋˜๋Š” SELECT ๋ฌธ๊ณผ ์™ธ๋ถ€์—์„œ ์‹คํ–‰๋˜๋Š” SELECT๋ฌธ์˜ ์ฐจ์ด๋Š” ์—†๋‹ค.
ํ•˜์ง€๋งŒ, Repeatable-Read์—์„œ๋Š” SELECT๊นŒ์ง€ ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„ ๋‚ด์—์„œ๋งŒ ์ž‘๋™ํ•˜์—ฌ ๊ณ„์† ๋™์ผํ•œ ๊ฒฐ๊ณผ๋งŒ ๋ณด์ด๋„๋ก ๋งŒ๋“ค๊ฒŒ ๋œ๋‹ค. ์ด์— ๋Œ€ํ•ด์„œ๋Š” ์•„๋ž˜์—์„œ ํ™•์ธํ•ด๋ณด์ž.
 


 

๐Ÿ’ฌ REPEATABLE READ

InnoDB์—์„œ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์œผ๋กœ, ๋ฐ”์ด๋„ˆ๋ฆฌ ๋กœ๊ทธ๋ฅผ ๊ฐ€์ง„ MySQL ์„œ๋ฒ„์—์„œ๋Š” ์ตœ์†Œ Repeatable read ์ด์ƒ์˜ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์„ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค. innoDB์—์„œ๋Š” MVCC๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ณ€๊ฒฝ ์ „ ๋ ˆ์ฝ”๋“œ๋ฅผ ์–ธ๋‘ ๊ณต๊ฐ„์— ๋ฐฑ์—…ํ•ด๋‘๊ณ , ์‹ค์ œ ๋ ˆ์ฝ”๋“œ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š”๋ฐ ์ด MVCC๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜์—์„œ๋Š” ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ฃผ๋„๋ก ๋ณด์žฅํ•œ๋‹ค.
๊ทผ๋ฐ ์•ž์„œ ๋ดค๋˜ Read Committed ์—ญ์‹œ ์–ธ๋‘ ๋กœ๊ทธ์— ์žˆ๋Š” ๊ฐ’์„ ๋ณด์—ฌ์คฌ์—ˆ๋Š”๋ฐ, repeatable read์™€ ๋ญ๊ฐ€ ๋‹ค๋ฅธ ๊ฒƒ์ผ๊นŒ?
์ด๋Š”, ์–ธ๋‘ ์˜์—ญ์— ๋ฐฑ์—…๋œ ๊ฐ’ ์ค‘ ๋ช‡ ๋ฒˆ์งธ ์ด์ „๊นŒ์ง€ ์ฐพ์•„ ๋“ค์–ด๊ฐ€๋Š”์ง€์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค.
 
์–ธ๋‘ ์˜์—ญ์—๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ณ€๊ฒฝ์„ ๋ฐœ์ƒ์‹œํ‚จ ํŠธ๋žœ์žญ์…˜์˜ ๋ฒˆํ˜ธ๋„ ํ•จ๊ป˜ ์ €์žฅํ•ด๋‘”๋‹ค. innoDB๋Š” ๋ถˆํ•„์š”ํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•˜๋Š” ์‹œ์ ์— ๊ณผ๊ฑฐ์˜ ์–ธ๋‘ ๋กœ๊ทธ๋ฅผ ์ œ๊ฑฐํ•˜๋Š”๋ฐ, ์ด๋•Œ ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ํŠธ๋žœ์žญ์…˜ ์ค‘ ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ๋ณด๋‹ค ์•ž์„  ์–ธ๋‘ ์˜์—ญ์˜ ๋ฐ์ดํ„ฐ๋Š” ์ œ๊ฑฐ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ์ •ํ™•ํ•˜๊ฒŒ๋Š”, ํŠน์ • ํŠธ๋žœ์žญ์…˜ ๊ตฌ๊ฐ„ ๋‚ด์—์„œ ๋ฐฑ์—…๋œ ์–ธ๋‘ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณด์กด๋˜์–ด์•ผ ํ•œ๋‹ค.

๊ทธ๋ฆผ์ด ๋„ˆ๋ฌด ์•„๋ž˜๋กœ ๊ธธ์–ด์ ธ์„œ ์–‘์˜†์œผ๋กœ ์ชผ๊ฐฐ๋‹ค.
๋จผ์ €, ์‚ฌ์šฉ์ž B๊ฐ€ ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— id = 1, name = hello์ธ ๋ ˆ์ฝ”๋“œ์™€ id = 2, name = journey์ธ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์กด์žฌํ–ˆ๋‹ค.
์ด๋•Œ select๋ฅผ ํ†ตํ•ด ์กฐํšŒํ–ˆ์„ ๋•Œ name = hello๋ฅผ ์กฐํšŒํ•˜์˜€๋‹ค.
 
์ดํ›„, ํŠธ๋žœ์žญ์…˜ ์•„์ด๋”” 12๋ฒˆ์ด update๋ฅผ ํ†ตํ•ด์„œ id = 1์˜ ๋ ˆ์ฝ”๋“œ์˜ name์„ hi๋กœ ๋ณ€๊ฒฝํ•˜์˜€๊ณ , ๋ณ€๊ฒฝ ์ „ ์‚ฌํ•ญ์— ๋Œ€ํ•ด ์–ธ๋‘ ๋กœ๊ทธ์— ๊ธฐ๋กํ•˜์˜€๋‹ค. ์ด๋•Œ, ์–ธ๋‘ ๋กœ๊ทธ์—๋Š” ๋ณ€๊ฒฝ ์ „ ํŠธ๋žœ์žญ์…˜ ์•„์ด๋””์ธ 6๋ฒˆ๋„ ํ•จ๊ป˜ ๊ธฐ๋ก๋˜์–ด ์žˆ๋‹ค.
 
์‚ฌ์šฉ์ž B๊ฐ€ ๋‹ค์‹œ id = 1์— ๋Œ€ํ•ด ์กฐํšŒ๋ฅผ ํ–ˆ์„ ๋•Œ ์–ธ๋‘ ๋กœ๊ทธ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๋Š”๋ฐ, ์ด๋•Œ ์‚ฌ์šฉ์ž B์˜ ํŠธ๋žœ์žญ์…˜ ์•„์ด๋””์ธ 10๋ณด๋‹ค ์ž‘์€ ์–ธ๋‘ ๋กœ๊ทธ์˜ ๊ฐ’์„ ํ™•์ธํ•˜์—ฌ ์กฐํšŒํ•˜๊ฒŒ ๋œ๋‹ค. ๋•๋ถ„์— ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜๋“  ์•ˆ ๋˜๋“  ํ•ญ์ƒ ๊ฐ™์€ name = hello์˜ ๊ฐ’์„ ์ฝ์–ด์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
์œ„ ๊ฒฝ์šฐ๋Š” ์˜ˆ์ œ๋ฅผ ๋‹จ์ˆœํ™”ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์–ธ๋‘ ์˜์—ญ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•˜๋‚˜์ง€๋งŒ, ๋‹น์—ฐํžˆ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ์žˆ๋‹ค. ํŠธ๋žœ์žญ์…˜์ด ๊ธธ์–ด์ง€๋ฉด ๊ธธ์–ด์งˆ์ˆ˜๋ก ์–ธ๋‘ ์˜์—ญ์˜ ๋ฐ์ดํ„ฐ ์—ญ์‹œ ๊ณ„์† ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— MySQL ์„œ๋ฒ„ ์„ฑ๋Šฅ์—๋„ ์˜ํ–ฅ์„ ๋ผ์นœ๋‹ค๋Š” ๊ฒƒ์„ ์ฃผ์˜ํ•˜์ž.
 
ํ•˜์ง€๋งŒ, ์ด ์—ญ์‹œ ๋ถ€์ •ํ•ฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฒ˜์Œ SELECT์—์„œ๋Š” journey๋งŒ ๋ฐ›์•„์˜ค์ง€๋งŒ, ๋‘ ๋ฒˆ์งธ SELECT์—์„œ journey์™€ cat์„ ๋ฐ›์•„์™”๋‹ค.
์ด๋ ‡๊ฒŒ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์— ์ˆ˜ํ–‰ํ•œ ๋ณ€๊ฒฝ ์ž‘์—…์— ์˜ํ•ด ๋ ˆ์ฝ”๋“œ๊ฐ€ ๋ณด์˜€๋‹ค ์•ˆ ๋ณด์˜€๋‹ค ํ•˜๋Š” ํ˜„์ƒ์„ 'Phantom Read' ๋ผ๊ณ  ํ•œ๋‹ค.
 
๊ธฐ๋ณธ์ ์œผ๋กœ select ... for update๋Š” ์“ฐ๊ธฐ ๋ฝ์„ ๊ฑธ์–ด์•ผ ํ•˜๋Š”๋ฐ, ์–ธ๋‘ ๋กœ๊ทธ์—๋Š” ๋ฝ์„ ๊ฑธ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— select ... for update๋‚˜ select ... lock in share mode๋กœ ์กฐํšŒ๋˜๋Š” ๋ ˆ์ฝ”๋“œ๋Š” ๋ณ€๊ฒฝ ์ „ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹Œ ํ˜„์žฌ ๋ ˆ์ฝ”๋“œ์˜ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค.
- select for update๋Š” ํŠน์ • ๋ ˆ์ฝ”๋“œ์— ๋Œ€ํ•ด์„œ X-Lock์„ ๊ฑฐ๋Š” ๊ตฌ๋ฌธ์ด๊ณ  (์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•ด์„œ ๋ฒ ํƒ€ ๋ฝ์„ ๊ฑฐ๋Š” ๋Š๋‚Œ), select lock in share mode๋Š” S-Lock์„ ๊ฑฐ๋Š” ๊ตฌ๋ฌธ์ด๋‹ค.
 

๐Ÿ’ก Non-Repeatable Read๋ž‘ ๋˜‘๊ฐ™์€ ๊ฑฐ ์•„๋‹๊นŒ?
 ์—ฌ๊ธฐ์„œ '๊ฒฐ๊ณผ์˜ ์ง‘ํ•ฉ์ด ๋‹ค๋ฅด๊ฒŒ ๋‚˜์™”๋‹ค'๋Š” ์ ์— ํฌ์ปค์Šค๋ฅผ ๋งž์ถฐ์•ผ ํ•œ๋‹ค. non-repeatable read์˜ ๊ฒฝ์šฐ 1๊ฐœ์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค์ง€๋งŒ, ์—…๋ฐ์ดํŠธ๋กœ ์ธํ•ด์„œ hello, hi๋ผ๋Š” 2๊ฐœ์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”๊ณ , ์—ฌ๊ธฐ์—์„œ๋Š” journey์™€ journey, cat์ด๋ผ๋Š” 2๊ฐœ์˜ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”๋‹ค. 
๋™์ผํ•œ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ๋™์ผํ•œ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋”๋ผ๋„ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์–ป๋Š”๋‹ค๋Š” ๊ฒŒ non-repeatable read์ด๊ณ , ๋‹ค๋ฅธ ๊ฒฐ๊ณผ ์ง‘ํ•ฉ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒŒ phantom-read์ด๋‹ค. non-repeatable read์˜ ๊ฒฝ์šฐ ์ˆ˜์ •๋œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ผ๊ด€์„ฑ ๋ฌธ์ œ๋ฅผ, phantom read์˜ ๊ฒฝ์šฐ ์‚ฝ์ž…์ด๋‚˜ ์‚ญ์ œ๋œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ผ๊ด€์„ฑ ๋ฌธ์ œ๋ฅผ ๊ฐ€์ง„๋‹ค.

 
 

๐Ÿ’ก InnoDB์—์„œ๋Š” ์™œ Phantom Read๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์„๊นŒ?

์ง€๋‚œ ํฌ์ŠคํŒ…์—์„œ ๋ดค๋“ฏ์ด, innoDB์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฝ ์ค‘์—์„œ '๋ ˆ์ฝ”๋“œ ๋ฝ'๊ณผ '๊ฐญ ๋ฝ'์„ ํ•ฉ์นœ '๋„ฅ์ŠคํŠธ ํ‚ค ๋ฝ'์„ ์ œ๊ณตํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. 

์œ„์™€ ๊ฐ™์ด ์‚ฌ์šฉ์ž B์˜ ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋˜๊ธฐ ์ „์— select ์‹œ ๋ฝ์„ ์žก๊ณ  ์žˆ์–ด์„œ ๊ณ„์† ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
 

โญ๏ธ ํ•˜์ง€๋งŒ, select ์ดํ›„ select for update๋กœ ์กฐํšŒํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ์–ธ๋‘ ์˜์—ญ์ด ์•„๋‹Œ ์›๋ณธ ํ…Œ์ด๋ธ”์˜ ๊ฐ’์„ ๋ฐ›์•„์˜ค๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ์˜ ๋ถ€์ •ํ•ฉ์ด ๋ฐœ์ƒํ•œ๋‹ค. ์ฆ‰, innoDB์—์„œ phantom read๊ฐ€ ๋ฌด์กฐ๊ฑด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค! select for update์˜ ๊ฒฝ์šฐ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
 


 
๐Ÿ’ฌ SERIALIZABLE

๊ฐ€์žฅ ๋‹จ์ˆœํ•˜๋ฉด์„œ๋„ ์—„๊ฒฉํ•œ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์ด๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€๋ณด๋‹ค ๋™์‹œ์„ฑ ์ž‘์—…์ด ๋–จ์–ด์ง„๋‹ค.
๊ธฐ๋ณธ์ ์œผ๋กœ innoDB ํ…Œ์ด๋ธ”์—์„œ ์ˆœ์ˆ˜ํ•œ select ์ž‘์—…์€ ๋ฝ ์—†์ด๋„ ์ˆ˜ํ–‰๋˜์ง€๋งŒ, serializable์—์„œ๋Š” ์ฝ๊ธฐ์— ๋Œ€ํ•ด์„œ๋„ S-Lock์„ ๊ฑธ์–ด์•ผ ํ•˜๋ฉฐ, ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์—์„œ๋Š” ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค. ์ด ๋•๋ถ„์— Phantom read ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜์ง€๋Š” ์•Š์ง€๋งŒ, innoDB์—์„œ๋Š” Gap Lock๊ณผ Next Key Lock ๋•๋ถ„์— repeatable read์—์„œ๋„ phantom read๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•„์„œ ๊ตณ์ด ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
 


 
์ฝ”๋“œ ๋ ˆ๋ฒจ๋กœ ์œ„ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์„ ํ™•์ธํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜ ํฌ์ŠคํŒ…์„ ํ™•์ธํ•ด ์ฃผ์„ธ์š” ๐Ÿ˜Š
[MySQL] ํŠธ๋žœ์žญ์…˜ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์„ ์ฟผ๋ฆฌ๋ฅผ ํ†ตํ•ด ์ง์ ‘ ํ…Œ์ŠคํŠธํ•ด๋ณด๊ธฐ
 

Comments