PostgreSQL ์•ˆํ‹ฐํŒจํ„ด: "์ฃฝ์€" ๋ฌด๋ฆฌ์™€ ์‹ธ์šฐ๊ธฐ

PostgreSQL์˜ ๋‚ด๋ถ€ ๋ฉ”์ปค๋‹ˆ์ฆ˜์˜ ํŠน์„ฑ์œผ๋กœ ์ธํ•ด ์–ด๋–ค ์ƒํ™ฉ์—์„œ๋Š” ๋งค์šฐ ๋น ๋ฅด์ง€๋งŒ ๋‹ค๋ฅธ ์ƒํ™ฉ์—์„œ๋Š” "๋ณ„๋กœ ๋น ๋ฅด์ง€ ์•Š์„" ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋Š˜ ์šฐ๋ฆฌ๋Š” DBMS์˜ ์ž‘๋™ ๋ฐฉ์‹๊ณผ ๊ฐœ๋ฐœ์ž๊ฐ€ DBMS๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—… ๊ฐ„์˜ ์ถฉ๋Œ์— ๋Œ€ํ•œ ์ „ํ˜•์ ์ธ ์˜ˆ์— โ€‹โ€‹์ค‘์ ์„ ๋‘˜ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—…๋ฐ์ดํŠธ์™€ MVCC ์›์น™.

์˜ ๊ฐ„๋žตํ•œ ์ด์•ผ๊ธฐ ํ›Œ๋ฅญํ•œ ๊ธฐ์‚ฌ:

UPDATE ๋ช…๋ น์œผ๋กœ ํ–‰์ด ์ˆ˜์ •๋˜๋ฉด ์‹ค์ œ๋กœ DELETE ๋ฐ INSERT๋ผ๋Š” ๋‘ ๊ฐ€์ง€ ์ž‘์—…์ด ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. ์•ˆ์— ๋ฌธ์ž์—ด์˜ ํ˜„์žฌ ๋ฒ„์ „ xmax๋Š” UPDATE๋ฅผ ์ˆ˜ํ–‰ํ•œ ํŠธ๋žœ์žญ์…˜์˜ ์ˆ˜์™€ ๋™์ผํ•˜๊ฒŒ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค ์ƒˆ ๋ฒ„์ „ ๊ฐ™์€ ์ค„; xmin ๊ฐ’์€ ์ด์ „ ๋ฒ„์ „์˜ xmax ๊ฐ’๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ฑฐ๋ž˜๊ฐ€ ์™„๋ฃŒ๋œ ํ›„ ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ์ด์ „ ๋ฒ„์ „ ๋˜๋Š” ์ƒˆ ๋ฒ„์ „์ด ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค. COMMIT/ROOLBACK, ์ธ์‹๋ฉ๋‹ˆ๋‹ค "์ฃฝ์Œ"(์ฃฝ์€ ํŠœํ”Œ) ์ง€๋‚˜๊ฐˆ ๋•Œ VACUUM ํ‘œ์— ๋”ฐ๋ผ ์ง€์›Œ์กŒ์Šต๋‹ˆ๋‹ค.

PostgreSQL ์•ˆํ‹ฐํŒจํ„ด: "์ฃฝ์€" ๋ฌด๋ฆฌ์™€ ์‹ธ์šฐ๊ธฐ

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ์ฆ‰์‹œ ์ผ์–ด๋‚˜์ง€๋Š” ์•Š์ง€๋งŒ "์ฃฝ์€"๋ฌธ์ œ๋Š” ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ํš๋“ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ก ๋Œ€๋Ÿ‰ ์—…๋ฐ์ดํŠธ ํฐ ํ…Œ์ด๋ธ”์—์„œ ์กฐ๊ธˆ ํ›„์— ๊ฐ™์€ ์ƒํ™ฉ์— ์ง๋ฉดํ•˜๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค VACUUM์€ ๋„์›€์„ ๋“œ๋ฆด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

#1: ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์˜ฎ๊ธฐ๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•œ๋‹ค

๊ท€ํ•˜์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ๋Œ€ํ•ด ์ž‘์—… ์ค‘์ธ๋ฐ ๊ฐ‘์ž๊ธฐ ์ผ๋ถ€ ๋ ˆ์ฝ”๋“œ์—์„œ X ํ•„๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๊นจ๋‹ซ๊ฒŒ ๋˜์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

UPDATE tbl SET X = <newX> WHERE pk = $1;

๊ทธ๋Ÿฐ ๋‹ค์Œ ์‹คํ–‰์ด ์ง„ํ–‰๋จ์— ๋”ฐ๋ผ Y ํ•„๋“œ๋„ ์—…๋ฐ์ดํŠธ๋˜์–ด์•ผ ํ•จ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

UPDATE tbl SET Y = <newY> WHERE pk = $1;

... ๊ทธ๋ฆฌ๊ณ  Z๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์™œ ์‚ฌ์†Œํ•œ ์ผ์— ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•ฉ๋‹ˆ๊นŒ?

UPDATE tbl SET Z = <newZ> WHERE pk = $1;

ํ˜„์žฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ด ๋ ˆ์ฝ”๋“œ์˜ ๋ฒ„์ „์ด ๋ช‡ ๊ฐœ ์žˆ์Šต๋‹ˆ๊นŒ? ์‘, 4๊ฐœ! ์ด ์ค‘ ํ•˜๋‚˜๋Š” ๊ด€๋ จ์ด ์žˆ์œผ๋ฉฐ 3๊ฐœ๋Š” [์ž๋™]VACUUM์œผ๋กœ ์ •๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฐ ์‹์œผ๋กœํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค! ์‚ฌ์šฉ ํ•˜๋‚˜์˜ ์š”์ฒญ์œผ๋กœ ๋ชจ๋“  ํ•„๋“œ ์—…๋ฐ์ดํŠธ โ€” ๊ฑฐ์˜ ํ•ญ์ƒ ๋ฉ”์†Œ๋“œ์˜ ๋…ผ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;

#2: ์‚ฌ์šฉ์€ DISTINCT FROM, Luke!

๊ทธ๋ž˜์„œ ๋‹น์‹ ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹โ€‹โ€‹์›ํ–ˆ์Šต๋‹ˆ๋‹ค ํ…Œ์ด๋ธ”์˜ ์ˆ˜๋งŽ์€ ๋ ˆ์ฝ”๋“œ ์—…๋ฐ์ดํŠธ (์˜ˆ๋ฅผ ๋“ค์–ด ์Šคํฌ๋ฆฝํŠธ๋‚˜ ๋ณ€ํ™˜๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ) ๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‚ด์šฉ์ด ์Šคํฌ๋ฆฝํŠธ์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2;

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

UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM <newX>;

๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์ด๋Ÿฐ ํ›Œ๋ฅญํ•œ ์šด์˜์ž์˜ ์กด์žฌ๋ฅผ ์•Œ์ง€ ๋ชปํ•˜๋ฏ€๋กœ ์—ฌ๊ธฐ์— ์น˜ํŠธ ์‹œํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. IS DISTINCT FROM ๊ทธ๋ฆฌ๊ณ  ๋„์›€์ด ๋˜๋Š” ๊ธฐํƒ€ ๋…ผ๋ฆฌ ์—ฐ์‚ฐ์ž:
PostgreSQL ์•ˆํ‹ฐํŒจํ„ด: "์ฃฝ์€" ๋ฌด๋ฆฌ์™€ ์‹ธ์šฐ๊ธฐ
... ๊ทธ๋ฆฌ๊ณ  ๋ณต์žกํ•œ ์ž‘์—…์— ๋Œ€ํ•ด ์กฐ๊ธˆ ROW()-ํ‘œํ˜„:
PostgreSQL ์•ˆํ‹ฐํŒจํ„ด: "์ฃฝ์€" ๋ฌด๋ฆฌ์™€ ์‹ธ์šฐ๊ธฐ

#3: ์ฐจ๋‹จ์„ ํ†ตํ•ด ๋‚ด ์—ฐ์ธ์„ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.

๋ฐœ์‚ฌ๋˜๊ณ ์žˆ๋‹ค ๋‘ ๊ฐœ์˜ ๋™์ผํ•œ ๋ณ‘๋ ฌ ํ”„๋กœ์„ธ์Šค, ๊ฐ๊ฐ์€ "์ง„ํ–‰ ์ค‘"์ด๋ผ๋Š” ํ•ญ๋ชฉ์„ ํ‘œ์‹œํ•˜๋ ค๊ณ  ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.

UPDATE tbl SET processing = TRUE WHERE pk = $1;

์ด๋Ÿฌํ•œ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹ค์ œ๋กœ ์„œ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ๋™์ผํ•œ ID ๋‚ด์—์„œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋”๋ผ๋„ ๋‘ ๋ฒˆ์งธ ํด๋ผ์ด์–ธํŠธ๋Š” ์ฒซ ๋ฒˆ์งธ ํŠธ๋žœ์žญ์…˜์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์ด ์š”์ฒญ์— ๋Œ€ํ•ด "์ž ๊ฒจ" ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ์ • ๋ฒˆํ˜ธ 1: ์ž‘์—…์ด ์ด์ „ ์ž‘์—…์œผ๋กœ ์ถ•์†Œ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์‹œ ์ถ”๊ฐ€ํ•ด๋ณด์ž IS DISTINCT FROM:

UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;

์ด ํ˜•์‹์—์„œ ๋‘ ๋ฒˆ์งธ ์š”์ฒญ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์–ด๋–ค ๊ฒƒ๋„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์œผ๋ฉฐ ๋ชจ๋“  ๊ฒƒ์ด ์ด๋ฏธ ์˜ˆ์ƒ๋Œ€๋กœ์ด๋ฏ€๋กœ ์ฐจ๋‹จ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์œผ๋กœ, ์ ์šฉ๋œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์—์„œ ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ๋ฅผ โ€œ์ฐพ์ง€ ๋ชปํ•จโ€์ด๋ผ๋Š” ์‚ฌ์‹ค์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ์ • ๋ฒˆํ˜ธ 2: ๊ถŒ๊ณ  ์ž ๊ธˆ

์ฝ์„ ์ˆ˜ ์žˆ๋Š” ๋ณ„๋„์˜ ๊ธฐ์‚ฌ์— ๋Œ€ํ•œ ํฐ ์ฃผ์ œ์ž…๋‹ˆ๋‹ค. ๊ถŒ์žฅ ์ฐจ๋‹จ์˜ ์ ์šฉ ๋ฐฉ๋ฒ• ๋ฐ "๊ฐˆํ€ด".

๊ฒฐ์ • ๋ฒˆํ˜ธ 3: ๋ฉ์ฒญํ•œ ์ „ํ™”

ํ•˜์ง€๋งŒ ์ด๊ฒƒ์ด ๋ฐ”๋กœ ๋‹น์‹ ์—๊ฒŒ ์ผ์–ด๋‚˜์•ผ ํ•  ์ผ์ž…๋‹ˆ๋‹ค ๋™์ผํ•œ ๋ ˆ์ฝ”๋“œ๋กœ ๋™์‹œ ์ž‘์—…? ์•„๋‹ˆ๋ฉด ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํ˜ธ์ถœํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ง์ณค์Šต๋‹ˆ๊นŒ? ๊ทธ๋ฆฌ๊ณ  ์ƒ๊ฐํ•ด๋ณด๋ฉด?..

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€