எம்விசிசி-3. சரம் பதிப்புகள்

எனவே, இது தொடர்பான பிரச்சினைகளை நாங்கள் பரிசீலித்தோம் காப்பு, மற்றும் பற்றி பின்வாங்கியது குறைந்த மட்டத்தில் தரவை ஒழுங்கமைத்தல். இறுதியாக நாங்கள் மிகவும் சுவாரஸ்யமான பகுதிக்கு வந்தோம் - சரம் பதிப்புகள்.

தலைப்பு

நாம் ஏற்கனவே கூறியது போல், ஒவ்வொரு வரிசையும் ஒரே நேரத்தில் தரவுத்தளத்தில் பல பதிப்புகளில் இருக்கலாம். ஒரு பதிப்பு எப்படியாவது மற்றொன்றிலிருந்து வேறுபடுத்தப்பட வேண்டும். இந்த நோக்கத்திற்காக, ஒவ்வொரு பதிப்பிலும் இந்த பதிப்பின் (xmin மற்றும் xmax) செயல்பாட்டின் "நேரத்தை" தீர்மானிக்கும் இரண்டு மதிப்பெண்கள் உள்ளன. மேற்கோள்களில் - ஏனெனில் இது பயன்படுத்தப்படும் நேரம் அல்ல, ஆனால் ஒரு சிறப்பு அதிகரிக்கும் கவுண்டர். மேலும் இந்த கவுண்டர் என்பது பரிவர்த்தனை எண்.

(வழக்கம் போல், உண்மை மிகவும் சிக்கலானது: கவுண்டரின் குறைந்த பிட் திறன் காரணமாக பரிவர்த்தனை எண்ணை எல்லா நேரத்திலும் அதிகரிக்க முடியாது. ஆனால் இந்த விவரங்களை நாம் உறைய வைக்கும் போது விரிவாகப் பார்ப்போம்.)

வரிசையை உருவாக்கும்போது, ​​INSERT கட்டளையை வழங்கிய பரிவர்த்தனை எண்ணுக்கு xmin அமைக்கப்படும், மேலும் xmax காலியாக விடப்படும்.

ஒரு வரிசையை நீக்கும் போது, ​​தற்போதைய பதிப்பின் xmax மதிப்பு, DELETE செய்த பரிவர்த்தனையின் எண்ணிக்கையுடன் குறிக்கப்படும்.

UPDATE கட்டளையால் ஒரு வரிசை மாற்றப்படும் போது, ​​இரண்டு செயல்பாடுகள் உண்மையில் செய்யப்படுகின்றன: DELETE மற்றும் INSERT. வரிசையின் தற்போதைய பதிப்பு, புதுப்பிப்பைச் செய்த பரிவர்த்தனையின் எண்ணிக்கைக்கு சமமாக xmax ஐ அமைக்கிறது. பின்னர் அதே சரத்தின் புதிய பதிப்பு உருவாக்கப்பட்டது; அதன் xmin மதிப்பு முந்தைய பதிப்பின் xmax மதிப்புடன் ஒத்துப்போகிறது.

xmin மற்றும் xmax புலங்கள் வரிசை பதிப்பு தலைப்பில் சேர்க்கப்பட்டுள்ளன. இந்த புலங்களுக்கு கூடுதலாக, தலைப்பு மற்றவற்றைக் கொண்டுள்ளது, எடுத்துக்காட்டாக:

  • infomask என்பது இந்த பதிப்பின் பண்புகளை வரையறுக்கும் பிட்களின் தொடர் ஆகும். அவற்றில் நிறைய உள்ளன; முக்கியவற்றை படிப்படியாகக் கருதுவோம்.
  • ctid என்பது அதே வரியின் அடுத்த புதிய பதிப்பிற்கான இணைப்பாகும். சரத்தின் புதிய, தற்போதைய பதிப்பிற்கு, ctid இந்த பதிப்பையே குறிக்கிறது. எண்ணில் படிவம் (x,y) உள்ளது, இங்கு x என்பது பக்க எண், y என்பது வரிசையில் உள்ள குறியீட்டு எண்.
  • பூஜ்ய பிட்மேப் - கொடுக்கப்பட்ட பதிப்பின் நெடுவரிசைகளைக் குறிக்கும், அதில் பூஜ்ய மதிப்பு (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 இல் உள்ள 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 (கமிட் லாக்) என்று அழைக்கப்பட்டது, மேலும் இந்த பெயரை இன்னும் வெவ்வேறு இடங்களில் காணலாம்).

XACT என்பது கணினி அட்டவணை அட்டவணை அல்ல; இவை PGDATA/pg_xact கோப்பகத்தில் உள்ள கோப்புகள். ஒவ்வொரு பரிவர்த்தனைக்கும் அவர்களுக்கு இரண்டு பிட்கள் ஒதுக்கப்பட்டுள்ளன: வரிசையின் பதிப்புத் தலைப்பைப் போலவே, உறுதியளிக்கப்பட்டது மற்றும் கைவிடப்பட்டது. இந்தத் தகவல் வசதிக்காக மட்டுமே பல கோப்புகளாகப் பிரிக்கப்பட்டுள்ளது; முடக்கம் செய்வதைக் கருத்தில் கொள்ளும்போது இந்தச் சிக்கலுக்குத் திரும்புவோம். இந்த கோப்புகளுடன் பணிபுரிவது மற்ற எல்லாவற்றிலும் பக்கம் பக்கமாக மேற்கொள்ளப்படுகிறது.

எனவே, XACT இல் பரிவர்த்தனை செய்யப்படும் போது, ​​இந்த பரிவர்த்தனைக்கு உறுதியான பிட் அமைக்கப்படும். இதுவே செய்யும் போது நடக்கும் அனைத்துமே (நாங்கள் இன்னும் முன் பதிவு பதிவு பற்றி பேசவில்லை என்றாலும்).

நாம் இப்போது பார்த்த அட்டவணைப் பக்கத்தை மற்றொரு பரிவர்த்தனை அணுகும்போது, ​​அது பல கேள்விகளுக்கு பதிலளிக்க வேண்டும்.

  1. xmin பரிவர்த்தனை முடிந்ததா? இல்லையெனில், சரத்தின் உருவாக்கப்பட்ட பதிப்பு தெரியவில்லை.
    இந்தச் சரிபார்ப்பு மற்றொரு கட்டமைப்பைப் பார்த்து செய்யப்படுகிறது, இது நிகழ்வின் பகிரப்பட்ட நினைவகத்தில் அமைந்துள்ளது மற்றும் இது ProcArray என்று அழைக்கப்படுகிறது. இது அனைத்து செயலில் உள்ள செயல்முறைகளின் பட்டியலையும் கொண்டுள்ளது, மேலும் ஒவ்வொன்றிற்கும் அதன் தற்போதைய (செயலில்) பரிவர்த்தனையின் எண்ணிக்கை குறிக்கப்படுகிறது.
  2. முடிந்தால், பிறகு எப்படி - செய்து அல்லது ரத்து செய்வது? ரத்துசெய்யப்பட்டால், வரிசையின் பதிப்பும் தெரியவில்லை.
    XACT என்பது இதுதான். ஆனால், XACT இன் கடைசிப் பக்கங்கள் ரேமில் உள்ள பஃபர்களில் சேமிக்கப்பட்டிருந்தாலும், ஒவ்வொரு முறையும் 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 முடிவடையும் வரை காத்திருக்க வேண்டிய கட்டாயம் ஏற்படும். தடுப்பது பற்றி பின்னர் பேசுவோம். இப்போதைக்கு, வரிசை பூட்டுகளின் எண்ணிக்கை வரம்பற்றது என்பதை நாங்கள் கவனிக்கிறோம். அவை ரேமில் இடத்தை எடுத்துக்கொள்வதில்லை மற்றும் கணினி செயல்திறன் அவற்றின் எண்ணிக்கையால் பாதிக்கப்படுவதில்லை. உண்மை, "நீண்ட" பரிவர்த்தனைகளுக்கு மற்ற குறைபாடுகள் உள்ளன, ஆனால் அது பின்னர்.

வரியை நீக்குவோம்.

=> 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-மரத்திற்கு, இலைப் பக்கங்களுடன் தொடர்புடைய வரிசைகள் அட்டவணையிடும் முக்கிய மதிப்பு மற்றும் தொடர்புடைய அட்டவணை வரிசையில் ஒரு குறிப்பு (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 இல் வரையறுக்கப்பட்டுள்ளது புள்ளிகளைச் சேமிக்கவும் (சேவ்பாயிண்ட்), இது பரிவர்த்தனையின் ஒரு பகுதியை முழுமையாக குறுக்கிடாமல் ரத்து செய்ய உங்களை அனுமதிக்கிறது. ஆனால் இது மேலே உள்ள வரைபடத்தில் பொருந்தாது, ஏனெனில் பரிவர்த்தனை அதன் அனைத்து மாற்றங்களுக்கும் ஒரே நிலையைக் கொண்டுள்ளது, மேலும் உடல் ரீதியாக எந்தத் தரவும் திரும்பப் பெறப்படவில்லை.

இந்தச் செயல்பாட்டைச் செயல்படுத்த, சேமிப்புப் புள்ளியுடன் கூடிய பரிவர்த்தனை பல தனித்தனியாகப் பிரிக்கப்படுகிறது உள்ளமை பரிவர்த்தனைகள் (துணை பரிவர்த்தனை), இதன் நிலையை தனித்தனியாக நிர்வகிக்கலாம்.

உள்ளமைக்கப்பட்ட பரிவர்த்தனைகள் அவற்றின் சொந்த எண்ணைக் கொண்டுள்ளன (முக்கிய பரிவர்த்தனையின் எண்ணிக்கையை விட அதிகம்). உள்ளமை பரிவர்த்தனைகளின் நிலை வழக்கமான முறையில் 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

கருத்தைச் சேர்