MVCC-3. තන්තු අනුවාද

එබැවින්, අපි සම්බන්ධ ගැටළු සලකා බැලුවෙමු පරිවාරක, සහ ගැන පසුබැසීමක් කළා අඩු මට්ටමක දත්ත සංවිධානය කිරීම. අවසාන වශයෙන් අපි වඩාත් රසවත් කොටස වෙත පැමිණියෙමු - නූල් අනුවාද.

ශීර්ෂකය

අප දැනටමත් පවසා ඇති පරිදි, සෑම පේළියක්ම දත්ත සමුදායේ අනුවාද කිහිපයක එකවර පැවතිය හැකිය. එක් අනුවාදයක් තවත් අනුවාදයකින් කෙසේ හෝ වෙන්කර හඳුනාගත යුතුය.මේ සඳහා, සෑම අනුවාදයකම මෙම අනුවාදයේ ක්‍රියාකාරීත්වයේ “කාලය” තීරණය කරන ලකුණු දෙකක් ඇත (xmin සහ xmax). උපුටා දැක්වීම් වලින් - එය භාවිතා කරනුයේ කාලය නොව, විශේෂ වැඩිවන කවුන්ටරයක් ​​නිසාය. තවද මෙම කවුන්ටරය ගනුදෙනු අංකය වේ.

(සුපුරුදු පරිදි, යථාර්ථය වඩාත් සංකීර්ණයි: කවුන්ටරයේ සීමිත බිට් ධාරිතාව නිසා ගනුදෙනු අංකය සෑම විටම වැඩි කළ නොහැක. නමුත් අපි ශීත කළ විට මෙම විස්තර විස්තරාත්මකව බලමු.)

පේළියක් සෑදූ විට, xmin INSERT විධානය නිකුත් කළ ගනුදෙනු අංකයට සකසා ඇති අතර, xmax හිස්ව තබයි.

පේළියක් මකා දැමූ විට, වත්මන් අනුවාදයේ xmax අගය DELETE සිදු කළ ගනුදෙනුවේ අංකය සමඟ ලකුණු කර ඇත.

UPDATE විධානයක් මඟින් පේළියක් වෙනස් කළ විට, මෙහෙයුම් දෙකක් ඇත්ත වශයෙන්ම සිදු කරනු ලැබේ: DELETE සහ INSERT. පේළියේ වත්මන් අනුවාදය යාවත්කාලීන කිරීම සිදු කළ ගනුදෙනුවේ අංකයට සමාන xmax සකසයි. එවිට එම තන්තුවේම නව අනුවාදයක් සාදනු ලැබේ; එහි xmin අගය පෙර අනුවාදයේ xmax අගය සමඟ සමපාත වේ.

xmin සහ xmax ක්ෂේත්‍ර පේළි අනුවාද ශීර්ෂයෙහි ඇතුළත් වේ. මෙම ක්ෂේත්‍ර වලට අමතරව, ශීර්ෂයේ වෙනත් දේ අඩංගු වේ, උදාහරණයක් ලෙස:

  • infomask යනු මෙම අනුවාදයේ ගුණාංග නිර්වචනය කරන බිටු මාලාවකි. ඒවායින් බොහොමයක් තිබේ; අපි ප්රධාන ඒවා ක්රමයෙන් සලකා බලමු.
  • ctid යනු එම පේළියේම ඊළඟ, නවතම අනුවාදයට සබැඳියකි. තන්තුවක නවතම, වඩාත්ම වත්මන් අනුවාදය සඳහා, ctid මෙම අනුවාදයටම යොමු කරයි. අංකයට පෝරමය (x,y) ඇත, x යනු පිටු අංකය වන අතර, y යනු අරාවේ ඇති දර්ශක අංකයයි.
  • null bitmap - ලබා දී ඇති අනුවාදයක null අගයක් (NULL) අඩංගු තීරු සලකුණු කරයි. NULL යනු සාමාන්‍ය දත්ත වර්ගයේ අගයන්ගෙන් එකක් නොවේ, එබැවින් ගුණාංගය වෙන වෙනම ගබඩා කළ යුතුය.

එහි ප්‍රතිඵලයක් වශයෙන්, ශීර්ෂය තරමක් විශාල වේ - පේළියේ එක් එක් අනුවාදය සඳහා අවම වශයෙන් බයිට් 23ක්, සහ සාමාන්‍යයෙන් NULL bitmap නිසා වැඩි වේ. වගුව "පටු" නම් (එනම්, තීරු කිහිපයක් අඩංගු වේ), උඩිස් වැඩ ප්‍රයෝජනවත් තොරතුරු වලට වඩා වැඩි ප්‍රමාණයක් ගත හැක.

ඇතුලත් කරන්න

ඇතුළත් කිරීමෙන් පටන් ගෙන පහත් මට්ටමේ තන්තු මෙහෙයුම් සිදු කරන්නේ කෙසේදැයි අපි වඩාත් සමීපව බලමු.

අත්හදා බැලීම් සඳහා, තීරු දෙකක් සහ ඒවායින් එකක් මත දර්ශකයක් සහිත නව වගුවක් නිර්මාණය කරමු:

=> 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 extension හි 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 හි Heap යන වචනය වගු වලට යොමු වන බව සලකන්න. මෙය මෙම යෙදුමේ තවත් අමුතු භාවිතයකි - ගොඩකි දත්ත ව්යුහය, මේසය සමඟ පොදු කිසිවක් නොමැති. මෙහිදී මෙම වචනය භාවිතා කරනු ලබන්නේ ඇණවුම් කරන ලද දර්ශක වලට ප්‍රතිවිරුද්ධව "සියල්ල එකට විසි කරනු ලැබේ" යන අර්ථයෙනි.

ශ්‍රිතය දත්ත “පවතින පරිදි”, තේරුම් ගැනීමට අපහසු ආකෘතියකින් පෙන්වයි. එය තේරුම් ගැනීමට, අපි තොරතුරු වලින් කොටසක් පමණක් ඉතිරි කර එය විකේතනය කරන්නෙමු:

=> 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: (පිටු අංකය, දර්ශක අංකය) ට සමාන ලෙස පෙනෙන පරිදි දර්ශක අංකයට බිංදුවක් එක් කරන ලදී.
  • 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 (commit log) ලෙස හැඳින්වූ අතර මෙම නම තවමත් විවිධ ස්ථානවල සොයාගත හැකිය).

XACT යනු පද්ධති නාමාවලි වගුවක් නොවේ; මේවා PGDATA/pg_xact නාමාවලියෙහි ඇති ගොනු වේ. ඔවුන්ට එක් එක් ගනුදෙනුව සඳහා බිටු දෙකක් ඇත: කැපවූ සහ ගබ්සා කරන ලද - පේළි අනුවාද ශීර්ෂයේ මෙන්. මෙම තොරතුරු පහසුව සඳහා පමණක් ගොනු කිහිපයකට බෙදා ඇත; අපි කැටි කිරීම සලකා බලන විට අපි මෙම ගැටලුව වෙත ආපසු යන්නෙමු. මෙම ලිපිගොනු සමඟ වැඩ කිරීම අනෙක් සියලුම මෙන් පිටුවෙන් පිටුව සිදු කෙරේ.

ඉතින්, XACT හි ගනුදෙනුවක් සිදු වූ විට, මෙම ගනුදෙනුව සඳහා කැපවූ බිට් එක සකසා ඇත. තවද මෙය සිදු කිරීමේදී සිදු වන්නේ මෙයයි (අපි තවමත් පූර්ව පටිගත කිරීමේ ලොගය ගැන කතා නොකරමු).

වෙනත් ගනුදෙනුවක් අප දැන් බැලූ වගු පිටුවට ප්‍රවේශ වූ විට, එයට ප්‍රශ්න කිහිපයකට පිළිතුරු දීමට සිදුවේ.

  1. xmin ගනුදෙනුව අවසන් වී තිබේද? එසේ නොවේ නම්, තන්තුවෙහි සාදන ලද අනුවාදය දෘශ්‍යමාන නොවිය යුතුය.
    මෙම චෙක්පත සිදු කරනු ලබන්නේ වෙනත් ව්‍යුහයක් දෙස බැලීමෙනි, එය උදාහරණයේ හවුල් මතකයේ පිහිටා ඇති අතර එය ProcArray ලෙස හැඳින්වේ. එහි සියලුම සක්‍රීය ක්‍රියාවලි ලැයිස්තුවක් අඩංගු වන අතර, එක් එක් සඳහා එහි වත්මන් (ක්‍රියාකාරී) ගනුදෙනුවේ අංකය දක්වා ඇත.
  2. සම්පූර්ණ කළහොත්, එසේ නම් - කැපවීමෙන් හෝ අවලංගු කිරීමෙන් කෙසේද? අවලංගු කළහොත්, පේළි අනුවාදය ද දෘශ්‍යමාන නොවිය යුතුය.
    XACT යනු හරියටම මෙයයි. නමුත්, XACT හි අවසාන පිටු RAM හි බෆරවල ගබඩා කර ඇතත්, සෑම විටම XACT පරීක්ෂා කිරීම තවමත් මිල අධිකය. එබැවින්, ගනුදෙනු තත්ත්වය තීරණය කළ පසු, එය string අනුවාදයේ 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-tree සතුව පාරදත්ත පිටුවක් සහ "සාමාන්‍ය" පිටු ඇත.

කෙසේ වෙතත්, පිටුවෙහි සාමාන්‍යයෙන් පේළි සහ පේළි වෙත දර්ශක මාලාවක් ඇත (වගු පිටුවක් මෙන්). ඊට අමතරව, පිටුවේ අවසානයේ විශේෂ දත්ත සඳහා ඉඩක් ඇත.

දර්ශකවල පේළි ද දර්ශක වර්ගය අනුව වෙනස් ව්‍යුහයන් තිබිය හැක. උදාහරණයක් ලෙස, B-tree සඳහා, පත්‍ර පිටුවලට අදාළ පේළිවල සුචිගත කිරීමේ යතුරු අගය සහ අදාළ වගු පේළියට යොමු (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 නිකුත් කරයි. අංකය ක්‍රියාවලි හැඳුනුම්පතකින් සහ අනුක්‍රමික අංකයකින් සමන්විත වේ.

මෙම අංකය නිකුත් කිරීම සියලු ක්රියාවලි අතර සමමුහුර්ත කිරීම අවශ්ය නොවන අතර එබැවින් ඉතා වේගවත් වේ. අපි කැටි කිරීම ගැන කතා කරන විට අතථ්‍ය අංක භාවිතා කිරීමට තවත් හේතුවක් ගැන අපි දැන හඳුනා ගනිමු.

දත්ත ස්නැප්ෂොට් වලදී අතථ්‍ය සංඛ්‍යා කිසිදු ආකාරයකින් සැලකිල්ලට නොගනී.

විවිධ කාලවලදී, දැනටමත් භාවිතා කර ඇති අංක සහිත පද්ධතියේ අතථ්‍ය ගනුදෙනු තිබිය හැකි අතර මෙය සාමාන්‍ය දෙයකි. නමුත් එවැනි අංකයක් දත්ත පිටුවලට ලිවිය නොහැක, මන්ද ඊළඟ වතාවේ පිටුවට ප්‍රවේශ වූ විට එහි සියලු අර්ථය නැති විය හැක.

=> 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 හි අර්ථ දක්වා ඇත ලකුණු ඉතිරි කරන්න (savepoint), එය ඔබට සම්පූර්ණයෙන්ම බාධාවකින් තොරව ගනුදෙනුවක කොටසක් අවලංගු කිරීමට ඉඩ සලසයි. නමුත් මෙය ඉහත රූප සටහනට නොගැලපේ, ගණුදෙනුවට එහි සියලුම වෙනස්කම් සඳහා එකම තත්ත්වය ඇති බැවින් සහ භෞතිකව කිසිදු දත්තයක් ආපසු හරවා නොගනී.

මෙම ක්‍රියාකාරීත්වය ක්‍රියාත්මක කිරීම සඳහා, සුරැකුම් ලක්ෂ්‍යයක් සහිත ගනුදෙනුවක් වෙන වෙනම කිහිපයකට බෙදා ඇත කැදලි ගනුදෙනු (උප ගනුදෙනු), එහි තත්ත්වය වෙන වෙනම කළමනාකරණය කළ හැක.

කැදලි ගනුදෙනුවලට ඔවුන්ගේම අංකයක් ඇත (ප්‍රධාන ගනුදෙනුවේ සංඛ්‍යාවට වඩා ඉහළ). කැදලි ගනුදෙනු වල තත්ත්වය 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 ඇත්ත වශයෙන්ම එක් එක් විධානයට පෙර ව්‍යංග සුරැකුම් ලක්ෂ්‍යයක් තබන බව අනුමාන කිරීම අපහසු නැත, අසාර්ථක වූ විට එය ආපසු හැරීමක් ආරම්භ කරයි. මෙම මාදිලිය පෙරනිමියෙන් භාවිතා නොකෙරේ, සුරැකුම් ස්ථාන සැකසීම (ඒවා වෙත ආපසු හැරවීමකින් තොරව පවා) සැලකිය යුතු පොදු කාර්යක් ඇතුළත් වේ.

අඛණ්ඩව.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න