MVCC-3. ๋ฌธ์ž์—ด ๋ฒ„์ „

๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ๊ด€๋ จ๋œ ๋ฌธ์ œ๋ฅผ ๊ณ ๋ คํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์—ด์žฌ, ๊ทธ๋ฆฌ๊ณ  ์•ฝ ํ‡ด๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค ๋‚ฎ์€ ์ˆ˜์ค€์—์„œ ๋ฐ์ดํ„ฐ ์ •๋ฆฌ. ๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ ๊ฐ€์žฅ ํฅ๋ฏธ๋กœ์šด ๋ถ€๋ถ„์ธ ๋ฌธ์ž์—ด ๋ฒ„์ „์— ๋„๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฆ„

์ด๋ฏธ ๋งํ–ˆ๋“ฏ์ด ๊ฐ ํ–‰์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์—ฌ๋Ÿฌ ๋ฒ„์ „์— ๋™์‹œ์— ์กด์žฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ ๋ฒ„์ „์€ ์–ด๋–ป๊ฒŒ๋“  ๋‹ค๋ฅธ ๋ฒ„์ „๊ณผ ๊ตฌ๋ณ„๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ๊ฐ ๋ฒ„์ „์—๋Š” ํ•ด๋‹น ๋ฒ„์ „์˜ ์ž‘์—… "์‹œ๊ฐ„"์„ ๊ฒฐ์ •ํ•˜๋Š” ๋‘ ๊ฐœ์˜ ํ‘œ์‹œ(xmin ๋ฐ xmax)๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ์˜ดํ‘œ๋กœ ๋ฌถ์Œ - ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์€ ์‹œ๊ฐ„์ด ์•„๋‹ˆ๋ผ ํŠน๋ณ„ํ•œ ์ฆ๊ฐ€ ์นด์šดํ„ฐ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ์นด์šดํ„ฐ๊ฐ€ ๊ฑฐ๋ž˜๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค.

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

ํ–‰์ด ์ƒ์„ฑ๋˜๋ฉด xmin์€ INSERT ๋ช…๋ น์„ ์‹คํ–‰ํ•œ ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ๋กœ ์„ค์ •๋˜๊ณ  xmax๋Š” ๊ณต๋ฐฑ์œผ๋กœ ๋‚จ์Šต๋‹ˆ๋‹ค.

ํ–‰์ด ์‚ญ์ œ๋˜๋ฉด ํ˜„์žฌ ๋ฒ„์ „์˜ xmax ๊ฐ’์— DELETE๋ฅผ ์ˆ˜ํ–‰ํ•œ ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

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

xmin ๋ฐ xmax ํ•„๋“œ๋Š” ํ–‰ ๋ฒ„์ „ ํ—ค๋”์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ํ—ค๋”์—๋Š” ์ด๋Ÿฌํ•œ ํ•„๋“œ ์™ธ์—๋„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ํ•„๋“œ๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

  • infomask๋Š” ์ด ๋ฒ„์ „์˜ ์†์„ฑ์„ ์ •์˜ํ•˜๋Š” ์ผ๋ จ์˜ ๋น„ํŠธ์ž…๋‹ˆ๋‹ค. ๊ฝค ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ ์ฐจ์ ์œผ๋กœ ์ฃผ์š” ๊ฒƒ๋“ค์„ ๊ณ ๋ คํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ctid๋Š” ๋™์ผํ•œ ์ค„์˜ ๋‹ค์Œ ์ตœ์‹  ๋ฒ„์ „์— ๋Œ€ํ•œ ๋งํฌ์ž…๋‹ˆ๋‹ค. ์ตœ์‹  ๋ฌธ์ž์—ด ๋ฒ„์ „์˜ ๊ฒฝ์šฐ ctid๋Š” ์ด ๋ฒ„์ „ ์ž์ฒด๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์ˆซ์ž์˜ ํ˜•์‹์€ (x,y)์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ x๋Š” ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ์ด๊ณ  y๋Š” ๋ฐฐ์—ด์˜ ์ธ๋ฑ์Šค ๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค.
  • null ๋น„ํŠธ๋งต - null ๊ฐ’(NULL)์„ ํฌํ•จํ•˜๋Š” ์ง€์ •๋œ ๋ฒ„์ „์˜ ์—ด์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. NULL์€ ์ผ๋ฐ˜ ๋ฐ์ดํ„ฐํ˜• ๊ฐ’์ด ์•„๋‹ˆ๋ฏ€๋กœ ์†์„ฑ์„ ๋ณ„๋„๋กœ ์ €์žฅํ•ด์•ผ ํ•œ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ ํ—ค๋”๋Š” ์ƒ๋‹นํžˆ ํฝ๋‹ˆ๋‹ค. ๊ฐ ๋ผ์ธ ๋ฒ„์ „์— ๋Œ€ํ•ด ์ตœ์†Œ 23๋ฐ”์ดํŠธ์ด๋ฉฐ ์ผ๋ฐ˜์ ์œผ๋กœ NULL ๋น„ํŠธ๋งต์œผ๋กœ ์ธํ•ด ๊ทธ ์ด์ƒ์ž…๋‹ˆ๋‹ค. ํ…Œ์ด๋ธ”์ด "์ข์€" ๊ฒฝ์šฐ(์ฆ‰, ์—ด์ด ๊ฑฐ์˜ ํฌํ•จ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ) ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์œ ์šฉํ•œ ์ •๋ณด๋ณด๋‹ค ๋” ๋งŽ์ด ์ฐจ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฝ์ž…

์‚ฝ์ž…๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ํ•˜์œ„ ์ˆ˜์ค€ ๋ฌธ์ž์—ด ์—ฐ์‚ฐ์ด ์ˆ˜ํ–‰๋˜๋Š” ๋ฐฉ์‹์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์‹คํ—˜์„ ์œ„ํ•ด ๋‘ ๊ฐœ์˜ ์—ด๊ณผ ๊ทธ ์ค‘ ํ•˜๋‚˜์— ์ธ๋ฑ์Šค๊ฐ€ ์žˆ๋Š” ์ƒˆ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

=> CREATE TABLE t(
  id serial,
  s text
);
=> CREATE INDEX ON t(s);

ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•œ ํ›„ ํ•˜๋‚˜์˜ ํ–‰์„ ์‚ฝ์ž…ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

=> BEGIN;
=> INSERT INTO t(s) VALUES ('FOO');

ํ˜„์žฌ ๊ฑฐ๋ž˜ ๋ฒˆํ˜ธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

=> SELECT txid_current();
 txid_current 
--------------
         3664
(1 row)

ํŽ˜์ด์ง€์˜ ๋‚ด์šฉ์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. pageinspect ํ™•์žฅ์˜ heap_page_items ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํฌ์ธํ„ฐ ๋ฐ ํ–‰ ๋ฒ„์ „์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

=> SELECT * FROM heap_page_items(get_raw_page('t',0)) gx
-[ RECORD 1 ]-------------------
lp          | 1
lp_off      | 8160
lp_flags    | 1
lp_len      | 32
t_xmin      | 3664
t_xmax      | 0
t_field3    | 0
t_ctid      | (0,1)
t_infomask2 | 2
t_infomask  | 2050
t_hoff      | 24
t_bits      | 
t_oid       | 
t_data      | x0100000009464f4f

PostgreSQL์—์„œ ํž™์ด๋ผ๋Š” ๋‹จ์–ด๋Š” ํ…Œ์ด๋ธ”์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์šฉ์–ด์˜ ๋˜ ๋‹ค๋ฅธ ์ด์ƒํ•œ ์‚ฌ์šฉ์ž…๋‹ˆ๋‹ค. ํž™์ด ์•Œ๋ ค์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ, ์ด๋Š” ํ…Œ์ด๋ธ”๊ณผ ๊ณตํ†ต์ ์ด ์—†์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ด ๋‹จ์–ด๋Š” ์ˆœ์„œ๊ฐ€ ์ง€์ •๋œ ์ƒ‰์ธ๊ณผ ๋‹ฌ๋ฆฌ "๋ชจ๋“  ๊ฒƒ์ด ํ•จ๊ป˜ ๋˜์ ธ์ง„๋‹ค"๋Š” ์˜๋ฏธ๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์€ ๋ฐ์ดํ„ฐ๋ฅผ "์žˆ๋Š” ๊ทธ๋Œ€๋กœ" ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์šด ํ˜•์‹์œผ๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•ด ์ •๋ณด์˜ ์ผ๋ถ€๋งŒ ๋‚จ๊ฒจ๋‘๊ณ  ํ•ด๋…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

=> SELECT '(0,'||lp||')' AS ctid,
       CASE lp_flags
         WHEN 0 THEN 'unused'
         WHEN 1 THEN 'normal'
         WHEN 2 THEN 'redirect to '||lp_off
         WHEN 3 THEN 'dead'
       END AS state,
       t_xmin as xmin,
       t_xmax as xmax,
       (t_infomask & 256) > 0  AS xmin_commited,
       (t_infomask & 512) > 0  AS xmin_aborted,
       (t_infomask & 1024) > 0 AS xmax_commited,
       (t_infomask & 2048) > 0 AS xmax_aborted,
       t_ctid
FROM heap_page_items(get_raw_page('t',0)) gx
-[ RECORD 1 ]-+-------
ctid          | (0,1)
state         | normal
xmin          | 3664
xmax          | 0
xmin_commited | f
xmin_aborted  | f
xmax_commited | f
xmax_aborted  | t
t_ctid        | (0,1)

์šฐ๋ฆฌ๊ฐ€ ํ•œ ์ผ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • t_ctid: (ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ, ์ƒ‰์ธ ๋ฒˆํ˜ธ)์™€ ๋™์ผํ•˜๊ฒŒ ๋ณด์ด๋„๋ก ์ƒ‰์ธ ๋ฒˆํ˜ธ์— XNUMX์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • lp_flags ํฌ์ธํ„ฐ์˜ ์ƒํƒœ๋ฅผ ํ•ด๋…ํ–ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” "์ •์ƒ"์ž…๋‹ˆ๋‹ค. ์ด๋Š” ํฌ์ธํ„ฐ๊ฐ€ ์‹ค์ œ๋กœ ๋ฌธ์ž์—ด ๋ฒ„์ „์„ ์ฐธ์กฐํ•œ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๋‹ค๋ฅธ ์˜๋ฏธ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
  • ๋ชจ๋“  ์ •๋ณด ๋น„ํŠธ ์ค‘์—์„œ ์ง€๊ธˆ๊นŒ์ง€ ๋‘ ์Œ๋งŒ ์‹๋ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. xmin_committed ๋ฐ xmin_aborted ๋น„ํŠธ๋Š” ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ xmin์ด ์ปค๋ฐ‹(์ค‘๋‹จ)๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๋‘ ๊ฐœ์˜ ์œ ์‚ฌํ•œ ๋น„ํŠธ๋Š” ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ xmax๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋ฌด์—‡์„ ๋ด…๋‹ˆ๊นŒ? ํ–‰์„ ์‚ฝ์ž…ํ•˜๋ฉด ํ–‰์˜ ์ฒซ ๋ฒˆ์งธ์ด์ž ์œ ์ผํ•œ ๋ฒ„์ „์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ธ๋ฑ์Šค ๋ฒˆํ˜ธ 1์ด ํ…Œ์ด๋ธ” ํŽ˜์ด์ง€์— ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

๋ฌธ์ž์—ด ๋ฒ„์ „์—์„œ xmin ํ•„๋“œ๋Š” ํ˜„์žฌ ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ๋กœ ์ฑ„์›Œ์ง‘๋‹ˆ๋‹ค. ํŠธ๋žœ์žญ์…˜์€ ์—ฌ์ „ํžˆ โ€‹โ€‹ํ™œ์„ฑ ์ƒํƒœ์ด๋ฏ€๋กœ xmin_committed ๋ฐ xmin_aborted ๋น„ํŠธ๊ฐ€ ๋ชจ๋‘ ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

ํ–‰ ๋ฒ„์ „ ctid ํ•„๋“œ๋Š” ๋™์ผํ•œ ํ–‰์„ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ตœ์‹  ๋ฒ„์ „์ด ์กด์žฌํ•˜์ง€ ์•Š์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

xmax ํ•„๋“œ๋Š” ํ–‰์˜ ์ด ๋ฒ„์ „์ด ์‚ญ์ œ๋˜์ง€ ์•Š์•˜์œผ๋ฉฐ ํ˜„์žฌ ๋ฒ„์ „์ด๋ฏ€๋กœ ๋”๋ฏธ ์ˆซ์ž 0์œผ๋กœ ์ฑ„์›Œ์ง‘๋‹ˆ๋‹ค. xmax_aborted ๋น„ํŠธ๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํŠธ๋žœ์žญ์…˜์€ ์ด ์ˆซ์ž์— ์ฃผ์˜๋ฅผ ๊ธฐ์šธ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

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

=> CREATE FUNCTION heap_page(relname text, pageno integer)
RETURNS TABLE(ctid tid, state text, xmin text, xmax text, t_ctid tid)
AS $$
SELECT (pageno,lp)::text::tid AS ctid,
       CASE lp_flags
         WHEN 0 THEN 'unused'
         WHEN 1 THEN 'normal'
         WHEN 2 THEN 'redirect to '||lp_off
         WHEN 3 THEN 'dead'
       END AS state,
       t_xmin || CASE
         WHEN (t_infomask & 256) > 0 THEN ' (c)'
         WHEN (t_infomask & 512) > 0 THEN ' (a)'
         ELSE ''
       END AS xmin,
       t_xmax || CASE
         WHEN (t_infomask & 1024) > 0 THEN ' (c)'
         WHEN (t_infomask & 2048) > 0 THEN ' (a)'
         ELSE ''
       END AS xmax,
       t_ctid
FROM heap_page_items(get_raw_page(relname,pageno))
ORDER BY lp;
$$ LANGUAGE SQL;

์ด ํ˜•์‹์—์„œ๋Š” ํ–‰ ๋ฒ„์ „์˜ ํ—ค๋”์—์„œ ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€๊ฐ€ ํ›จ์”ฌ ๋” ๋ช…ํ™•ํ•ด์ง‘๋‹ˆ๋‹ค.

=> SELECT * FROM heap_page('t',0);
 ctid  | state  | xmin | xmax  | t_ctid 
-------+--------+------+-------+--------
 (0,1) | normal | 3664 | 0 (a) | (0,1)
(1 row)

์œ ์‚ฌํ•˜์ง€๋งŒ ํ›จ์”ฌ ๋œ ์ƒ์„ธํ•œ ์ •๋ณด๋Š” ์˜์‚ฌ ์—ด xmin ๋ฐ xmax๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ด๋ธ” ์ž์ฒด์—์„œ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3664 |    0 |  1 | FOO
(1 row)

๊ณ ์ •

ํŠธ๋žœ์žญ์…˜์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋˜๋ฉด ํ•ด๋‹น ์ƒํƒœ๋ฅผ ๊ธฐ์–ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋˜์—ˆ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”. ์ด๋ฅผ ์œ„ํ•ด XACT๋ผ๋Š” ๊ตฌ์กฐ๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค(๋ฒ„์ „ 10 ์ด์ „์—๋Š” CLOG(์ปค๋ฐ‹ ๋กœ๊ทธ)๋ผ๊ณ  ๋ถˆ๋ €์œผ๋ฉฐ ์ด ์ด๋ฆ„์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋‹ค๋ฅธ ์œ„์น˜์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค).

XACT๋Š” ์‹œ์Šคํ…œ ์นดํƒˆ๋กœ๊ทธ ํ…Œ์ด๋ธ”์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ด๋Š” PGDATA/pg_xact ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์žˆ๋Š” ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ํ–‰ ๋ฒ„์ „ ํ—ค๋”์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ฐ ํŠธ๋žœ์žญ์…˜์— ๋Œ€ํ•ด ์ปค๋ฐ‹ ๋ฐ ์ค‘๋‹จ์ด๋ผ๋Š” ๋‘ ๋น„ํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ •๋ณด๋Š” ํŽธ์˜์ƒ ์—ฌ๋Ÿฌ ํŒŒ์ผ๋กœ ๋‚˜๋ˆ„์–ด์ ธ ์žˆ์œผ๋ฉฐ, ๋™๊ฒฐ์„ ๊ณ ๋ คํ•  ๋•Œ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋‹ค์‹œ ์–ธ๊ธ‰ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฌํ•œ ํŒŒ์ผ ์ž‘์—…์€ ๋‹ค๋ฅธ ๋ชจ๋“  ํŒŒ์ผ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํŽ˜์ด์ง€๋ณ„๋กœ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ XACT์—์„œ ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋˜๋ฉด ์ปค๋ฐ‹๋œ ๋น„ํŠธ๊ฐ€ ์ด ํŠธ๋žœ์žญ์…˜์— ๋Œ€ํ•ด ์„ค์ •๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ปค๋ฐ‹ ์ค‘์— ์ผ์–ด๋‚˜๋Š” ๋ชจ๋“  ์ผ์ž…๋‹ˆ๋‹ค(์‚ฌ์ „ ๊ธฐ๋ก ๋กœ๊ทธ์— ๋Œ€ํ•ด์„œ๋Š” ์•„์ง ์–ธ๊ธ‰ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ).

๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ๋ฐฉ๊ธˆ ์‚ดํŽด๋ณธ ํ…Œ์ด๋ธ” ํŽ˜์ด์ง€์— ์•ก์„ธ์Šคํ•˜๋ฉด ๋ช‡ ๊ฐ€์ง€ ์งˆ๋ฌธ์— ๋‹ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  1. xmin ํŠธ๋žœ์žญ์…˜์ด ์™„๋ฃŒ๋˜์—ˆ๋‚˜์š”? ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ƒ์„ฑ๋œ ๋ฌธ์ž์—ด ๋ฒ„์ „์ด ํ‘œ์‹œ๋˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    ์ด ๊ฒ€์‚ฌ๋Š” ์ธ์Šคํ„ด์Šค์˜ ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ์— ์žˆ๊ณ  ProcArray๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๋‹ค๋ฅธ ๊ตฌ์กฐ๋ฅผ ์‚ดํŽด๋ด„์œผ๋กœ์จ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ๋ชจ๋“  ํ™œ์„ฑ ํ”„๋กœ์„ธ์Šค์˜ ๋ชฉ๋ก์ด ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ ๊ฐ ํ”„๋กœ์„ธ์Šค์— ๋Œ€ํ•ด ํ˜„์žฌ(ํ™œ์„ฑ) ํŠธ๋žœ์žญ์…˜ ์ˆ˜๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
  2. ์™„๋ฃŒ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ์ปค๋ฐ‹ํ•˜๊ฑฐ๋‚˜ ์ทจ์†Œํ•ฉ๋‹ˆ๊นŒ? ์ทจ์†Œํ•˜๋ฉด ํ–‰ ๋ฒ„์ „๋„ ํ‘œ์‹œ๋˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    ์ด๊ฒƒ์ด ๋ฐ”๋กœ XACT์˜ ๋ชฉ์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ XACT์˜ ๋งˆ์ง€๋ง‰ ํŽ˜์ด์ง€๊ฐ€ RAM์˜ ๋ฒ„ํผ์— ์ €์žฅ๋˜์–ด ์žˆ๋”๋ผ๋„ ๋งค๋ฒˆ XACT๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒƒ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๋น„์šฉ์ด ๋งŽ์ด ๋“ญ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํŠธ๋žœ์žญ์…˜ ์ƒํƒœ๊ฐ€ ๊ฒฐ์ •๋˜๋ฉด ๋ฌธ์ž์—ด ๋ฒ„์ „์˜ xmin_committed ๋ฐ xmin_aborted ๋น„ํŠธ์— ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋น„ํŠธ ์ค‘ ํ•˜๋‚˜๊ฐ€ ์„ค์ •๋˜๋ฉด ํŠธ๋žœ์žญ์…˜ xmin์˜ ์ƒํƒœ๋Š” ์•Œ๋ ค์ง„ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋˜๋ฉฐ ๋‹ค์Œ ํŠธ๋žœ์žญ์…˜์€ XACT์— ์•ก์„ธ์Šคํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

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

๋น„์šฉ ์ ˆ๊ฐ์˜ ๋‹จ์ ์€ ๋ณ€๊ฒฝ ํ›„ ๋ชจ๋“  ํŠธ๋žœ์žญ์…˜(๊ฐ„๋‹จํ•œ ์ฝ๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ํŠธ๋žœ์žญ์…˜์ด๋ผ๋„ - SELECT)์ด ๋ฒ„ํผ ์บ์‹œ์˜ ๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ˆ˜์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

=> COMMIT;

ํŽ˜์ด์ง€์—๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค(๊ทธ๋Ÿฌ๋‚˜ ๊ฑฐ๋ž˜ ์ƒํƒœ๋Š” ์ด๋ฏธ XACT์— ๊ธฐ๋ก๋˜์–ด ์žˆ์Œ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค).

=> SELECT * FROM heap_page('t',0);
 ctid  | state  | xmin | xmax  | t_ctid 
-------+--------+------+-------+--------
 (0,1) | normal | 3664 | 0 (a) | (0,1)
(1 row)

์ด์ œ ํŽ˜์ด์ง€์— ๋จผ์ € ์•ก์„ธ์Šคํ•˜๋Š” ํŠธ๋žœ์žญ์…˜์€ xmin ํŠธ๋žœ์žญ์…˜ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๊ณ  ์ด๋ฅผ ์ •๋ณด ๋น„ํŠธ์— ์จ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

=> SELECT * FROM t;
 id |  s  
----+-----
  1 | FOO
(1 row)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3664 (c) | 0 (a) | (0,1)
(1 row)

์ œ๊ฑฐ

ํ–‰์ด ์‚ญ์ œ๋˜๋ฉด ํ˜„์žฌ ์‚ญ์ œ ํŠธ๋žœ์žญ์…˜์˜ ๋ฒˆํ˜ธ๊ฐ€ ํ˜„์žฌ ๋ฒ„์ „์˜ xmax ํ•„๋“œ์— ๊ธฐ๋ก๋˜๊ณ  xmax_aborted ๋น„ํŠธ๊ฐ€ ์ง€์›Œ์ง‘๋‹ˆ๋‹ค.

ํ™œ์„ฑ ํŠธ๋žœ์žญ์…˜์— ํ•ด๋‹นํ•˜๋Š” xmax ์„ค์ • ๊ฐ’์€ ํ–‰ ์ž ๊ธˆ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ์ด ํ–‰์„ ์—…๋ฐ์ดํŠธํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜๋ ค๋Š” ๊ฒฝ์šฐ xmax ํŠธ๋žœ์žญ์…˜์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฐจ๋‹จ์— ๋Œ€ํ•ด์„œ๋Š” ๋‚˜์ค‘์— ๋” ์ž์„ธํžˆ ์ด์•ผ๊ธฐํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ ํ–‰ ์ž ๊ธˆ ์ˆ˜๊ฐ€ ๋ฌด์ œํ•œ์ด๋ผ๋Š” ์ ๋งŒ ์•Œ์•„๋‘๊ฒ ์Šต๋‹ˆ๋‹ค. RAM ๊ณต๊ฐ„์„ ์ฐจ์ง€ํ•˜์ง€ ์•Š์œผ๋ฉฐ ์‹œ์Šคํ…œ ์„ฑ๋Šฅ์ด ๊ทธ ์ˆ˜๋กœ ์ธํ•ด ์ €ํ•˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‚ฌ์‹ค, "์žฅ๊ธฐ" ํŠธ๋žœ์žญ์…˜์—๋Š” ๋‹ค๋ฅธ ๋‹จ์ ๋„ ์žˆ์ง€๋งŒ ์ด์— ๋Œ€ํ•ด์„œ๋Š” ๋‚˜์ค‘์— ์ž์„ธํžˆ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๋‹น ์ค„์„ ์‚ญ์ œํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

=> BEGIN;
=> DELETE FROM t;
=> SELECT txid_current();
 txid_current 
--------------
         3665
(1 row)

ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ๊ฐ€ xmax ํ•„๋“œ์— ๊ธฐ๋ก๋˜์–ด ์žˆ์ง€๋งŒ ์ •๋ณด ๋น„ํŠธ๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์€ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax | t_ctid 
-------+--------+----------+------+--------
 (0,1) | normal | 3664 (c) | 3665 | (0,1)
(1 row)

๋ง์†Œ

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

=> ROLLBACK;
=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax | t_ctid 
-------+--------+----------+------+--------
 (0,1) | normal | 3664 (c) | 3665 | (0,1)
(1 row)

ํŽ˜์ด์ง€์— ์•ก์„ธ์Šคํ•˜๋ฉด ์ƒํƒœ๊ฐ€ ํ™•์ธ๋˜๊ณ  xmax_aborted ํžŒํŠธ ๋น„ํŠธ๊ฐ€ ํ–‰ ๋ฒ„์ „์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค. xmax ์ˆซ์ž ์ž์ฒด๋Š” ํŽ˜์ด์ง€์— ๋‚จ์•„ ์žˆ์ง€๋งŒ ๋ˆ„๊ตฌ๋„ ์ด๋ฅผ ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

=> SELECT * FROM t;
 id |  s  
----+-----
  1 | FOO
(1 row)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   |   xmax   | t_ctid 
-------+--------+----------+----------+--------
 (0,1) | normal | 3664 (c) | 3665 (a) | (0,1)
(1 row)

์—…๋ฐ์ดํŠธ

์—…๋ฐ์ดํŠธ๋Š” ํ–‰์˜ ํ˜„์žฌ ๋ฒ„์ „์„ ๋จผ์ € ์‚ญ์ œํ•œ ๋‹ค์Œ ์ƒˆ ๋ฒ„์ „์„ ์‚ฝ์ž…ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

=> BEGIN;
=> UPDATE t SET s = 'BAR';
=> SELECT txid_current();
 txid_current 
--------------
         3666
(1 row)

์ฟผ๋ฆฌ๋Š” ํ•œ ์ค„(์ƒˆ ๋ฒ„์ „)์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

=> SELECT * FROM t;
 id |  s  
----+-----
  1 | BAR
(1 row)

ํ•˜์ง€๋งŒ ํŽ˜์ด์ง€์—๋Š” ๋‘ ๊ฐ€์ง€ ๋ฒ„์ „์ด ๋ชจ๋‘ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3664 (c) | 3666  | (0,2)
 (0,2) | normal | 3666     | 0 (a) | (0,2)
(2 rows)

์‚ญ์ œ๋œ ๋ฒ„์ „์€ xmax ํ•„๋“œ์— ํ˜„์žฌ ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ์ด์ „ ๊ฑฐ๋ž˜๊ฐ€ ์ทจ์†Œ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ฐ’์€ ์ด์ „ ๊ฐ’ ์œ„์— ์“ฐ์—ฌ์ง‘๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  xmax_aborted ๋น„ํŠธ๋Š” ํ˜„์žฌ ํŠธ๋žœ์žญ์…˜์˜ ์ƒํƒœ๊ฐ€ ์•„์ง ์•Œ๋ ค์ง€์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ง€์›Œ์ง‘๋‹ˆ๋‹ค.

์ด์ œ ํ–‰์˜ ์ฒซ ๋ฒˆ์งธ ๋ฒ„์ „์€ ๋‘ ๋ฒˆ์งธ(t_ctid ํ•„๋“œ)๋ฅผ ์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ ์ธ๋ฑ์Šค๋Š” ์ธ๋ฑ์Šค ํŽ˜์ด์ง€์— ๋‚˜ํƒ€๋‚˜๊ณ  ๋‘ ๋ฒˆ์งธ ํ–‰์€ ํ…Œ์ด๋ธ” ํŽ˜์ด์ง€์˜ ๋‘ ๋ฒˆ์งธ ๋ฒ„์ „์„ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค.

์‚ญ์ œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ–‰์˜ ์ฒซ ๋ฒˆ์งธ ๋ฒ„์ „์— ์žˆ๋Š” xmax ๊ฐ’์€ ํ–‰์ด ์ž ๊ฒจ ์žˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

์ž, ๊ฑฐ๋ž˜๋ฅผ ์™„๋ฃŒํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

=> COMMIT;

์ง€์ˆ˜

์ง€๊ธˆ๊นŒ์ง€ ์šฐ๋ฆฌ๋Š” ํ…Œ์ด๋ธ” ํŽ˜์ด์ง€์— ๋Œ€ํ•ด์„œ๋งŒ ์ด์•ผ๊ธฐํ–ˆ์Šต๋‹ˆ๋‹ค. ์ธ๋ฑ์Šค ๋‚ด๋ถ€์—์„œ๋Š” ์–ด๋–ค ์ผ์ด ๋ฐœ์ƒํ•˜๋‚˜์š”?

์ธ๋ฑ์Šค ํŽ˜์ด์ง€์˜ ์ •๋ณด๋Š” ํŠน์ • ์ธ๋ฑ์Šค ์œ ํ˜•์— ๋”ฐ๋ผ ํฌ๊ฒŒ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•œ ์œ ํ˜•์˜ ์ธ๋ฑ์Šค๋ผ๋„ ๋‹ค์–‘ํ•œ ์œ ํ˜•์˜ ํŽ˜์ด์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด B-ํŠธ๋ฆฌ์—๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€์™€ "์ผ๋ฐ˜" ํŽ˜์ด์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ํŽ˜์ด์ง€์—๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ–‰๊ณผ ํ–‰ ์ž์ฒด์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ ๋ฐฐ์—ด์ด ์žˆ์Šต๋‹ˆ๋‹ค(ํ…Œ์ด๋ธ” ํŽ˜์ด์ง€์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ). ๋˜ํ•œ ํŽ˜์ด์ง€ ๋์—๋Š” ํŠน๋ณ„ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์œ„ํ•œ ๊ณต๊ฐ„์ด ์žˆ์Šต๋‹ˆ๋‹ค.

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

๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ ์€ ๋ชจ๋“  ์œ ํ˜•์˜ ์ธ๋ฑ์Šค์— ํ–‰ ๋ฒ„์ „์ด ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ธ€์Ž„, ์•„๋‹ˆ๋ฉด ๊ฐ ์ค„์ด ์ •ํ™•ํžˆ ํ•˜๋‚˜์˜ ๋ฒ„์ „์œผ๋กœ ํ‘œํ˜„๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์ธ๋ฑ์Šค ํ–‰ ํ—ค๋”์—๋Š” xmin ๋ฐ xmax ํ•„๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ธ๋ฑ์Šค์˜ ๋งํฌ๊ฐ€ ํ–‰์˜ ๋ชจ๋“  โ€‹โ€‹ํ…Œ์ด๋ธ” ๋ฒ„์ „์œผ๋กœ ์—ฐ๊ฒฐ๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ…Œ์ด๋ธ”์„ ์‚ดํŽด๋ณด๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ํŠธ๋žœ์žญ์…˜์— ์–ด๋–ค ๋ฒ„์ „์ด ํ‘œ์‹œ๋˜๋Š”์ง€ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (ํ•ญ์ƒ ๊ทธ๋ ‡๋“ฏ์ด ์ด๊ฒƒ์ด ์ „๋ถ€ ์ง„์‹ค์€ ์•„๋‹™๋‹ˆ๋‹ค. ๊ฒฝ์šฐ์— ๋”ฐ๋ผ ๊ฐ€์‹œ์„ฑ ๋งต์ด ํ”„๋กœ์„ธ์Šค๋ฅผ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ด์— ๋Œ€ํ•ด์„œ๋Š” ๋‚˜์ค‘์— ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.)

๋™์‹œ์—, ์ƒ‰์ธ ํŽ˜์ด์ง€์—์„œ ์šฐ๋ฆฌ๋Š” ํ˜„์žฌ ๋ฒ„์ „๊ณผ ์ด์ „ ๋ฒ„์ „ ๋ชจ๋‘์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.

=> SELECT itemoffset, ctid FROM bt_page_items('t_s_idx',1);
 itemoffset | ctid  
------------+-------
          1 | (0,2)
          2 | (0,1)
(2 rows)

๊ฐ€์ƒ ๊ฑฐ๋ž˜

์‹ค์ œ๋กœ PostgreSQL์€ ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ๋ฅผ "์ €์žฅ"ํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ์ ํ™”๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํŠธ๋žœ์žญ์…˜์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ธฐ๋งŒ ํ•˜๋Š” ๊ฒฝ์šฐ ํ–‰ ๋ฒ„์ „์˜ ๊ฐ€์‹œ์„ฑ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์„œ๋น„์Šค ํ”„๋กœ์„ธ์Šค๋Š” ๋จผ์ € ๊ฐ€์ƒ xid๋ฅผ ํŠธ๋žœ์žญ์…˜์— ๋ฐœ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค. ๋ฒˆํ˜ธ๋Š” ํ”„๋กœ์„ธ์Šค ID์™€ ์‹œํ€€์Šค ๋ฒˆํ˜ธ๋กœ ๊ตฌ์„ฑ๋ฉ๋‹ˆ๋‹ค.

์ด ๋ฒˆํ˜ธ๋ฅผ ๋ฐœ๊ธ‰ํ•˜๋Š” ๋ฐ๋Š” ๋ชจ๋“  ํ”„๋กœ์„ธ์Šค ๊ฐ„์˜ ๋™๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋งค์šฐ ๋น ๋ฆ…๋‹ˆ๋‹ค. ๋™๊ฒฐ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•  ๋•Œ ๊ฐ€์ƒ ๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ์ด์œ ๋ฅผ ์•Œ๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฐ€์ƒ ๋ฒˆํ˜ธ๋Š” ๋ฐ์ดํ„ฐ ์Šค๋ƒ…์ƒท์—์„œ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ๋„ ๊ณ ๋ ค๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์„œ๋กœ ๋‹ค๋ฅธ ์‹œ์ ์— ์ด๋ฏธ ์‚ฌ์šฉ๋œ ๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹œ์Šคํ…œ์— ๊ฐ€์ƒ ํŠธ๋žœ์žญ์…˜์ด ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด๋Š” ์ •์ƒ์ ์ธ ํ˜„์ƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฌํ•œ ์ˆซ์ž๋Š” ๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€์— ๊ธฐ๋ก๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋‹ค์Œ์— ํŽ˜์ด์ง€์— ์•ก์„ธ์Šคํ•  ๋•Œ ๋ชจ๋“  ์˜๋ฏธ๋ฅผ ์žƒ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

=> BEGIN;
=> SELECT txid_current_if_assigned();
 txid_current_if_assigned 
--------------------------
                         
(1 row)

ํŠธ๋žœ์žญ์…˜์ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด ์‹ค์ œ ๊ณ ์œ  ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ๊ฐ€ ๋ถ€์—ฌ๋ฉ๋‹ˆ๋‹ค.

=> UPDATE accounts SET amount = amount - 1.00;
=> SELECT txid_current_if_assigned();
 txid_current_if_assigned 
--------------------------
                     3667
(1 row)

=> COMMIT;

์ค‘์ฒฉ๋œ ํŠธ๋žœ์žญ์…˜

ํฌ์ธํŠธ ์ €์žฅ

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

์ด ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ €์žฅ์ ์ด ์žˆ๋Š” ํŠธ๋žœ์žญ์…˜์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ฐœ๋ณ„ ํ•ญ๋ชฉ์œผ๋กœ ๋ถ„ํ• ๋ฉ๋‹ˆ๋‹ค. ์ค‘์ฒฉ๋œ ํŠธ๋žœ์žญ์…˜ (ํ•˜์œ„ ๊ฑฐ๋ž˜)์˜ ์ƒํƒœ๋ฅผ ๋ณ„๋„๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์ฒฉ๋œ ํŠธ๋žœ์žญ์…˜์—๋Š” ๊ณ ์œ ํ•œ ๋ฒˆํ˜ธ(๊ธฐ๋ณธ ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ๋ณด๋‹ค ๋†’์Œ)๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ค‘์ฒฉ๋œ ํŠธ๋žœ์žญ์…˜์˜ ์ƒํƒœ๋Š” XACT์—์„œ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ์‹์œผ๋กœ ๊ธฐ๋ก๋˜์ง€๋งŒ ์ตœ์ข… ์ƒํƒœ๋Š” ๊ธฐ๋ณธ ํŠธ๋žœ์žญ์…˜์˜ ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ์ฆ‰, ์ทจ์†Œ๋˜๋ฉด ๋ชจ๋“  ์ค‘์ฒฉ๋œ ํŠธ๋žœ์žญ์…˜๋„ ์ทจ์†Œ๋ฉ๋‹ˆ๋‹ค.

ํŠธ๋žœ์žญ์…˜ ์ค‘์ฒฉ์— ๋Œ€ํ•œ ์ •๋ณด๋Š” PGDATA/pg_subtrans ๋””๋ ‰ํ„ฐ๋ฆฌ์˜ ํŒŒ์ผ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ์€ XACT ๋ฒ„ํผ์™€ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ๊ตฌ์„ฑ๋œ ์ธ์Šคํ„ด์Šค ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ์˜ ๋ฒ„ํผ๋ฅผ ํ†ตํ•ด ์•ก์„ธ์Šค๋ฉ๋‹ˆ๋‹ค.

์ค‘์ฒฉ ํŠธ๋žœ์žญ์…˜๊ณผ ์ž์œจ ํŠธ๋žœ์žญ์…˜์„ ํ˜ผ๋™ํ•˜์ง€ ๋งˆ์„ธ์š”. ์ž์œจ ํŠธ๋žœ์žญ์…˜์€ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ๋“  ์„œ๋กœ ์˜์กดํ•˜์ง€ ์•Š์ง€๋งŒ ์ค‘์ฒฉ ํŠธ๋žœ์žญ์…˜์€ ์˜์กดํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜ PostgreSQL์—๋Š” ์ž์œจ ํŠธ๋žœ์žญ์…˜์ด ์—†์œผ๋ฉฐ ์•„๋งˆ๋„ ์ตœ์„ ์„ ๋‹คํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋งค์šฐ ๋“œ๋ฌผ๊ฒŒ ํ•„์š”ํ•˜๋ฉฐ ๋‹ค๋ฅธ DBMS์— ์กด์žฌํ•˜๋ฉด ๋‚จ์šฉ์„ ์œ ๋ฐœํ•˜์—ฌ ๋ชจ๋“  ์‚ฌ๋žŒ์ด ๊ณ ํ†ต์„ ๊ฒช๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

ํ…Œ์ด๋ธ”์„ ์ง€์šฐ๊ณ  ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•œ ํ›„ ํ–‰์„ ์‚ฝ์ž…ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

=> TRUNCATE TABLE t;
=> BEGIN;
=> INSERT INTO t(s) VALUES ('FOO');
=> SELECT txid_current();
 txid_current 
--------------
         3669
(1 row)

=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3669 |    0 |  2 | FOO
(1 row)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  | xmin | xmax  | t_ctid 
-------+--------+------+-------+--------
 (0,1) | normal | 3669 | 0 (a) | (0,1)
(1 row)

์ด์ œ ์ €์žฅ์ ์„ ๋‘๊ณ  ๋‹ค๋ฅธ ์ค„์„ ์‚ฝ์ž…ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

=> SAVEPOINT sp;
=> INSERT INTO t(s) VALUES ('XYZ');
=> SELECT txid_current();
 txid_current 
--------------
         3669
(1 row)

txid_current() ํ•จ์ˆ˜๋Š” ์ค‘์ฒฉ๋œ ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ๊ฐ€ ์•„๋‹Œ ๊ธฐ๋ณธ ํŠธ๋žœ์žญ์…˜ ๋ฒˆํ˜ธ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”.

=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3669 |    0 |  2 | FOO
 3670 |    0 |  3 | XYZ
(2 rows)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  | xmin | xmax  | t_ctid 
-------+--------+------+-------+--------
 (0,1) | normal | 3669 | 0 (a) | (0,1)
 (0,2) | normal | 3670 | 0 (a) | (0,2)
(2 rows)

์ €์žฅ ์ง€์ ์œผ๋กœ ๋กค๋ฐฑํ•˜๊ณ  ์„ธ ๋ฒˆ์งธ ์ค„์„ ์‚ฝ์ž…ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

=> ROLLBACK TO sp;
=> INSERT INTO t(s) VALUES ('BAR');
=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3669 |    0 |  2 | FOO
 3671 |    0 |  4 | BAR
(2 rows)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3669     | 0 (a) | (0,1)
 (0,2) | normal | 3670 (a) | 0 (a) | (0,2)
 (0,3) | normal | 3671     | 0 (a) | (0,3)
(3 rows)

ํŽ˜์ด์ง€์—๋Š” ์ทจ์†Œ๋œ ์ค‘์ฒฉ ํŠธ๋žœ์žญ์…˜์— ์˜ํ•ด ์ถ”๊ฐ€๋œ ํ–‰์ด ๊ณ„์† ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

=> COMMIT;
=> SELECT xmin, xmax, * FROM t;
 xmin | xmax | id |  s  
------+------+----+-----
 3669 |    0 |  2 | FOO
 3671 |    0 |  4 | BAR
(2 rows)

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3669 (c) | 0 (a) | (0,1)
 (0,2) | normal | 3670 (a) | 0 (a) | (0,2)
 (0,3) | normal | 3671 (c) | 0 (a) | (0,3)
(3 rows)

์ด์ œ ์ค‘์ฒฉ๋œ ๊ฐ ํŠธ๋žœ์žญ์…˜๋งˆ๋‹ค ๊ณ ์œ ํ•œ ์ƒํƒœ๊ฐ€ ์žˆ์Œ์„ ๋ช…ํ™•ํ•˜๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ค‘์ฒฉ๋œ ํŠธ๋žœ์žญ์…˜์€ SQL์—์„œ ๋ช…์‹œ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ฆ‰, ํ˜„์žฌ ํŠธ๋žœ์žญ์…˜์„ ์™„๋ฃŒํ•˜์ง€ ์•Š๊ณ ๋Š” ์ƒˆ ํŠธ๋žœ์žญ์…˜์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์ €์žฅ์ ์„ ์‚ฌ์šฉํ•  ๋•Œ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ PL/pgSQL ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ์™€ ๊ธฐํƒ€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ํŠน์ดํ•œ ๊ฒฝ์šฐ์—์„œ ์•”์‹œ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค.

=> BEGIN;
BEGIN
=> BEGIN;
WARNING:  there is already a transaction in progress
BEGIN
=> COMMIT;
COMMIT
=> COMMIT;
WARNING:  there is no transaction in progress
COMMIT

์ž‘์—…์˜ ์˜ค๋ฅ˜ ๋ฐ ์›์ž์„ฑ

์ž‘์—… ์ˆ˜ํ–‰ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋‚˜์š”? ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

=> BEGIN;
=> SELECT * FROM t;
 id |  s  
----+-----
  2 | FOO
  4 | BAR
(2 rows)

=> UPDATE t SET s = repeat('X', 1/(id-4));
ERROR:  division by zero

์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ํŠธ๋žœ์žญ์…˜์€ ์ค‘๋‹จ๋œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋˜์–ด ์–ด๋– ํ•œ ์ž‘์—…๋„ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

=> SELECT * FROM t;
ERROR:  current transaction is aborted, commands ignored until end of transaction block

๊ทธ๋ฆฌ๊ณ  ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ปค๋ฐ‹ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋”๋ผ๋„ PostgreSQL์€ ์ค‘๋‹จ์„ ๋ณด๊ณ ํ•ฉ๋‹ˆ๋‹ค.

=> COMMIT;
ROLLBACK

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

=> SELECT * FROM heap_page('t',0);
 ctid  | state  |   xmin   | xmax  | t_ctid 
-------+--------+----------+-------+--------
 (0,1) | normal | 3669 (c) | 3672  | (0,4)
 (0,2) | normal | 3670 (a) | 0 (a) | (0,2)
 (0,3) | normal | 3671 (c) | 0 (a) | (0,3)
 (0,4) | normal | 3672     | 0 (a) | (0,4)
(4 rows)

psql์—๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ์—ฐ์‚ฐ์ž์˜ ์ž‘์—…์ด ๋กค๋ฐฑ๋œ ๊ฒƒ์ฒ˜๋Ÿผ ์˜ค๋ฅ˜ ํ›„์—๋„ ํŠธ๋žœ์žญ์…˜์„ ๊ณ„์†ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“œ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

=> set ON_ERROR_ROLLBACK on
=> BEGIN;
=> SELECT * FROM t;
 id |  s  
----+-----
  2 | FOO
  4 | BAR
(2 rows)

=> UPDATE t SET s = repeat('X', 1/(id-4));
ERROR:  division by zero

=> SELECT * FROM t;
 id |  s  
----+-----
  2 | FOO
  4 | BAR
(2 rows)

=> COMMIT;

์ด ๋ชจ๋“œ์—์„œ psql์€ ์‹ค์ œ๋กœ ๊ฐ ๋ช…๋ น ์•ž์— ์•”์‹œ์  ์ €์žฅ ์ง€์ ์„ ๋‘๊ณ  ์‹คํŒจํ•  ๊ฒฝ์šฐ ๋กค๋ฐฑ์„ ์‹œ์ž‘ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์ถ”์ธกํ•˜๊ธฐ ์–ด๋ ต์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ €์žฅ์ ์„ ์„ค์ •ํ•˜๋ฉด(๋กค๋ฐฑํ•˜์ง€ ์•Š๊ณ ๋„) ์ƒ๋‹นํ•œ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ์ด ๋ชจ๋“œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ณ„์†.

์ถœ์ฒ˜ : habr.com

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