๊ทธ๋์ ์ฐ๋ฆฌ๋ ๊ด๋ จ๋ ๋ฌธ์ ๋ฅผ ๊ณ ๋ คํ์ต๋๋ค.
์ด๋ฆ
์ด๋ฏธ ๋งํ๋ฏ์ด ๊ฐ ํ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฌ๋ฌ ๋ฒ์ ์ ๋์์ ์กด์ฌํ ์ ์์ต๋๋ค. ํ ๋ฒ์ ์ ์ด๋ป๊ฒ๋ ๋ค๋ฅธ ๋ฒ์ ๊ณผ ๊ตฌ๋ณ๋์ด์ผ ํฉ๋๋ค. ์ด๋ฅผ ์ํด ๊ฐ ๋ฒ์ ์๋ ํด๋น ๋ฒ์ ์ ์์ "์๊ฐ"์ ๊ฒฐ์ ํ๋ ๋ ๊ฐ์ ํ์(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์์ ํธ๋์ญ์ ์ด ์ปค๋ฐ๋๋ฉด ์ปค๋ฐ๋ ๋นํธ๊ฐ ์ด ํธ๋์ญ์ ์ ๋ํด ์ค์ ๋ฉ๋๋ค. ์ด๊ฒ์ด ์ปค๋ฐ ์ค์ ์ผ์ด๋๋ ๋ชจ๋ ์ผ์ ๋๋ค(์ฌ์ ๊ธฐ๋ก ๋ก๊ทธ์ ๋ํด์๋ ์์ง ์ธ๊ธํ์ง ์์์ง๋ง).
๋ค๋ฅธ ํธ๋์ญ์ ์ด ๋ฐฉ๊ธ ์ดํด๋ณธ ํ ์ด๋ธ ํ์ด์ง์ ์ก์ธ์คํ๋ฉด ๋ช ๊ฐ์ง ์ง๋ฌธ์ ๋ตํด์ผ ํฉ๋๋ค.
- xmin ํธ๋์ญ์
์ด ์๋ฃ๋์๋์? ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ ์์ฑ๋ ๋ฌธ์์ด ๋ฒ์ ์ด ํ์๋์ง ์์์ผ ํฉ๋๋ค.
์ด ๊ฒ์ฌ๋ ์ธ์คํด์ค์ ๊ณต์ ๋ฉ๋ชจ๋ฆฌ์ ์๊ณ ProcArray๋ผ๊ณ ๋ถ๋ฆฌ๋ ๋ค๋ฅธ ๊ตฌ์กฐ๋ฅผ ์ดํด๋ด์ผ๋ก์จ ์ํ๋ฉ๋๋ค. ์ฌ๊ธฐ์๋ ๋ชจ๋ ํ์ฑ ํ๋ก์ธ์ค์ ๋ชฉ๋ก์ด ํฌํจ๋์ด ์์ผ๋ฉฐ ๊ฐ ํ๋ก์ธ์ค์ ๋ํด ํ์ฌ(ํ์ฑ) ํธ๋์ญ์ ์๊ฐ ํ์๋ฉ๋๋ค. - ์๋ฃ๋๋ฉด ์ด๋ป๊ฒ ์ปค๋ฐํ๊ฑฐ๋ ์ทจ์ํฉ๋๊น? ์ทจ์ํ๋ฉด ํ ๋ฒ์ ๋ ํ์๋์ง ์์์ผ ํฉ๋๋ค.
์ด๊ฒ์ด ๋ฐ๋ก 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์ ์ค์ ๋ก ๊ฐ ๋ช ๋ น ์์ ์์์ ์ ์ฅ ์ง์ ์ ๋๊ณ ์คํจํ ๊ฒฝ์ฐ ๋กค๋ฐฑ์ ์์ํ๋ค๋ ๊ฒ์ ์ถ์ธกํ๊ธฐ ์ด๋ ต์ง ์์ต๋๋ค. ์ ์ฅ์ ์ ์ค์ ํ๋ฉด(๋กค๋ฐฑํ์ง ์๊ณ ๋) ์๋นํ ์ค๋ฒํค๋๊ฐ ๋ฐ์ํ๋ฏ๋ก ์ด ๋ชจ๋๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ฉ๋์ง ์์ต๋๋ค.