MVCC-3. Vérsi string

Janten, urang parantos nganggap masalah anu aya hubunganana insulasi, sarta dijieun mundur ngeunaan ngatur data dina tingkat handap. Sarta pamustunganana urang meunang ka bagian paling metot - versi string.

lulugu

Sakumaha anu parantos kami nyarios, unggal baris sakaligus tiasa aya dina sababaraha versi dina pangkalan data. Hiji vérsi kedah kumaha waé dibédakeun tina anu sanés. Pikeun tujuan ieu, unggal vérsi ngagaduhan dua tanda anu nangtukeun "waktos" tindakan versi ieu (xmin sareng xmax). Dina tanda petik - sabab teu waktos sapertos nu dipaké, tapi hiji counter ngaronjatna husus. Sareng counter ieu mangrupikeun nomer transaksi.

(Saperti biasa, kanyataanana leuwih pajeulit: jumlah urus teu bisa ningkatkeun sadaya waktu alatan kapasitas bit kawates counter. Tapi urang bakal kasampak di rinci ieu di jéntré lamun urang meunang ka katirisan.)

Nalika barisan dijieun, xmin disetel ka nomer transaksi anu ngaluarkeun paréntah INSERT, sarta xmax ditinggalkeun kosong.

Nalika barisan dihapus, nilai xmax tina versi ayeuna ditandaan ku jumlah transaksi anu ngalaksanakeun DELETE.

Lamun baris dirobah ku paréntah UPDATE, dua operasi sabenerna dipigawé: DELETE jeung INSERT. Versi baris ayeuna susunan xmax sarua jeung jumlah transaksi anu dipigawé UPDATE. A versi anyar tina string sarua lajeng dijieun; nilai xmin na coincides jeung nilai xmax tina versi saméméhna.

Widang xmin sareng xmax kalebet dina header versi baris. Salian widang ieu, lulugu ngandung batur, contona:

  • infomask mangrupakeun runtuyan bit nu nangtukeun sipat versi ieu. Aya rada loba di antarana; Urang laun-laun bakal mertimbangkeun anu utama.
  • ctid mangrupakeun tumbu ka hareup, versi anyar tina garis sarua. Pikeun newest, versi panganyarna tina string a, ctid nujul kana versi ieu sorangan. Jumlahna ngagaduhan bentuk (x,y), dimana x mangrupikeun nomer halaman, y mangrupikeun nomer indéks dina susunan.
  • null bitmap - Nyirian kolom dina versi tinangtu nu ngandung nilai null (null). NULL sanes salah sahiji nilai tipe data normal, jadi atribut kudu disimpen misah.

Hasilna, lulugu anu cukup badag - sahenteuna 23 bait pikeun tiap versi garis, sarta biasana leuwih alatan bitmap NULL. Lamun tabél "sempit" (nyaéta, ngandung sababaraha kolom), overhead nu bisa nyandak up leuwih ti informasi mangpaat.

ngasupkeun

Hayu urang tingali kumaha operasi senar tingkat handap dilaksanakeun, dimimitian ku sisipan.

Pikeun ékspérimén, hayu urang jieun tabel anyar sareng dua kolom sareng indéks dina salah sahijina:

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

Hayu urang selapkeun hiji baris sanggeus dimimitian transaksi.

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

Ieu nomer transaksi kami ayeuna:

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

Hayu urang nempo eusi kaca. Fungsi heap_page_items tina ekstensi pageinspect ngamungkinkeun anjeun kéngingkeun inpormasi ngeunaan petunjuk sareng versi baris:

=> 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

Catet yén kecap tumpukan dina PostgreSQL nujul kana tabel. Ieu pamakéan aneh sejen tina istilah - numpuk dipikawanoh struktur data, nu boga nanaon di umum kalawan tabél. Di dieu kecap dipaké dina harti "sagala dialungkeun babarengan," sabalikna indexes maréntahkeun.

Fungsi nembongkeun data "sakumaha aya", dina format anu hese ngarti. Pikeun terangna, urang ngan ukur ngantunkeun bagian tina inpormasi sareng decipher:

=> 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)

Ieu naon anu urang lakukeun:

  • Ditambahkeun hiji enol kana angka indéks sangkan eta kasampak sarua t_ctid: (nomer kaca, angka indéks).
  • Deciphered kaayaan pointer lp_flags. Di dieu éta "normal" - ieu ngandung harti yén pointer sabenerna nujul kana versi string. Urang bakal nempo harti séjén engké.
  • Tina sadaya bit inpormasi, ngan ukur dua pasang anu parantos dikenalkeun dugi ka ayeuna. Bit xmin_committed sareng xmin_aborted nunjukkeun naha jumlah transaksi xmin komitmen (digugurkeun). Dua bit sarupa nujul kana angka transaksi xmax.

Naon anu urang tingali? Lamun anjeun nyelapkeun baris, hiji angka indéks 1 bakal muncul dina kaca tabel, nunjuk ka versi munggaran tur hijina baris.

Dina versi string, widang xmin dieusian ku jumlah transaksi ayeuna. Transaksina masih aktip, janten bit xmin_committed sareng xmin_aborted henteu disetel.

Widang ctid versi baris ngarujuk kana baris anu sami. Ieu ngandung harti yén versi anyar teu aya.

Widang xmax dieusian ku angka dummy 0 sabab versi baris ieu teu acan dihapus sarta ayeuna. Transaksi moal nengetan angka ieu sabab bit xmax_aborted diatur.

Hayu urang nyandak hiji lengkah deui pikeun ngaronjatkeun readability ku nambahkeun bit informasi ka nomer transaksi. Sareng hayu urang nyiptakeun fungsi, sabab urang peryogi pamundut langkung ti sakali:

=> 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;

Dina formulir ieu, leuwih jelas naon anu lumangsung dina lulugu versi baris:

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

Sarupa, tapi sacara signifikan kurang rinci, inpormasi tiasa didapet tina tabel sorangan, nganggo pseudo-columns xmin sareng xmax:

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

Fixation

Upami transaksi parantos réngsé, anjeun kedah émut statusna - perhatikeun yén éta komitmen. Pikeun ngalakukeun ieu, struktur anu disebut XACT dianggo (sareng sateuacan versi 10 disebut CLOG (commit log) sareng nami ieu masih tiasa dipendakan di tempat anu béda).

XACT sanes tabel katalog sistem; Ieu mangrupikeun file dina diréktori PGDATA / pg_xact. Aranjeunna gaduh dua bit anu dialokasikeun pikeun unggal urus: komitmen sareng dibatalkeun - sapertos dina header versi baris. Inpormasi ieu dibagi kana sababaraha file ngan ukur pikeun genah; urang bakal uih deui ka masalah ieu nalika urang nganggap katirisan. Sareng damel sareng file ieu dilaksanakeun halaman demi halaman, sapertos sadayana anu sanés.

Janten, nalika transaksi dilakukeun dina XACT, bit komitmen diatur pikeun transaksi ieu. Sareng ieu sadayana anu kajantenan nalika ngalakukeun (sanaos urang henteu acan ngobrol ngeunaan log pre-recording).

Nalika transaksi anu sanés ngaksés halaman méja anu urang tingali, éta kedah ngajawab sababaraha patarosan.

  1. Naha transaksi xmin parantos réngsé? Upami henteu, maka versi senar anu diciptakeun henteu kedah katingali.
    Cék ieu dilakukeun ku ningali struktur anu sanés, anu aya dina mémori anu dibagikeun dina conto sareng disebut ProcArray. Ieu ngandung daptar sadaya prosés aktip, sarta pikeun tiap hiji jumlah transaksi ayeuna (aktip) dituduhkeun.
  2. Upami réngsé, teras kumaha - ku komitmen atanapi ngabatalkeun? Upami dibolaykeun, versi barisna ogé henteu tiasa katingali.
    Ieu kahayang pikeun XACT. Tapi, sanajan kaca panungtungan of XACT disimpen dina buffers dina RAM, masih mahal pikeun pariksa XACT unggal waktu. Ku alatan éta, nalika status urus ditangtukeun, éta ditulis kana bit xmin_committed na xmin_aborted tina versi string. Upami salah sahiji bit ieu diatur, maka kaayaan transaksi xmin dianggap dipikanyaho sareng transaksi salajengna henteu kedah ngaksés XACT.

Naha bit ieu henteu diatur ku urus sorangan ngalakukeun sisipan? Nalika sisipan lumangsung, urus henteu acan terang naha éta bakal suksés. Sarta dina momen committing, geus euweuh jelas garis nu mana kaca dirobah. Panginten seueur halaman sapertos kitu, sareng ngapalkeunana henteu nguntungkeun. Sajaba ti éta, sababaraha kaca bisa digusur tina cache panyangga kana disk; maca aranjeunna deui pikeun ngarobah bit bakal ngalambatkeun commit sacara signifikan.

The downside tina tabungan éta sanggeus parobahan, sagala transaksi (malah hiji ngajalankeun basajan dibaca - PILIH) bisa dimimitian ngarobah kaca data dina cache panyangga.

Ku kituna, hayu urang ngalereskeun parobahanana.

=> COMMIT;

Henteu aya anu robih dina halaman (tapi urang terang yén status transaksi parantos kacatet dina XACT):

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

Ayeuna transaksi anu ngaksés halaman heula kedah nangtukeun status transaksi xmin sareng nyerat kana bit inpormasi:

=> 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)

Ngahapus

Nalika barisan dihapus, jumlah transaksi ngahapus ayeuna ditulis kana widang xmax versi ayeuna, sarta bit xmax_aborted diberesihan.

Catet yén nilai set tina xmax saluyu sareng transaksi aktip bertindak salaku konci baris. Upami transaksi anu sanés hoyong ngapdet atanapi ngahapus baris ieu, éta bakal kapaksa ngadagoan transaksi xmax réngsé. Urang bakal ngobrol ngeunaan meungpeuk engké. Pikeun ayeuna mah, urang ngan dicatet yén jumlah konci baris henteu kawates. Aranjeunna henteu nyandak rohangan dina RAM sareng kinerja sistem henteu kakurangan tina jumlahna. Leres, transaksi "panjang" gaduh kalemahan sanés, tapi langkung seueur ngeunaan éta engké.

Hayu urang mupus garis.

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

Kami ningali yén nomer transaksi ditulis dina widang xmax, tapi bit inpormasi henteu diatur:

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

pembatalan

Aborting parobahan jalan sarupa committing, ngan dina XACT bit aborted diatur pikeun urus. Undoing téh sagancangna committing. Sanajan paréntah disebut ROLLBACK, parobahan teu digulung deui: sagalana yén urus junun robah dina kaca data tetep unchanged.

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

Nalika kaca diaksés, statusna bakal dipariksa sarta bit hint xmax_aborted bakal disetel ka versi baris. Jumlah xmax sorangan tetep dina kaca, tapi teu saurang ogé bakal nempo eta.

=> 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)

Apdet

Pembaruanna tiasa dianggo saolah-olah mimiti ngahapus versi barisan ayeuna teras diselapkeun anu énggal.

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

Patarosan ngahasilkeun hiji baris (versi anyar):

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

Tapi dina kaca urang ningali duanana versi:

=> 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)

Versi dihapus ditandaan ku nomer transaksi ayeuna dina widang xmax. Leuwih ti éta, nilai ieu ditulis leuwih hiji heubeul, saprak urus saméméhna ieu dibolaykeun. Jeung bit xmax_aborted diberesihan sabab status tina transaksi ayeuna teu acan dipikawanoh.

Versi kahiji garis ayeuna nujul kana kadua (sawah t_ctid) salaku nu leuwih anyar.

Indéks kadua némbongan dina halaman indéks sareng baris kadua ngarujuk kana versi kadua dina halaman méja.

Sagampil sareng ngahapus, nilai xmax dina versi kahiji baris mangrupa indikasi yen baris dikonci.

Muhun, hayu urang ngalengkepan transaksi.

=> COMMIT;

Indéks

Sajauh kami geus ngan dikaitkeun kaca tabel. Naon anu lumangsung di jero indéks?

Inpo dina kaca indéks variasina greatly gumantung kana tipe husus tina indéks. Komo hiji tipe indéks boga tipena béda kaca. Contona, hiji B-tangkal boga kaca metadata jeung "biasa" kaca.

Sanajan kitu, kaca biasana boga Asép Sunandar Sunarya ti pointers ka baris jeung barisan sorangan (kawas kaca tabel). Salaku tambahan, dina tungtung halaman aya rohangan pikeun data khusus.

Baris dina indéks ogé bisa mibanda struktur pisan béda gumantung kana jenis indéks. Contona, pikeun B-tangkal, baris patali kaca daun ngandung nilai konci indéks jeung rujukan (ctid) kana baris tabel pakait. Sacara umum, indéks bisa terstruktur dina cara lengkep beda.

Titik anu paling penting nyaéta henteu aya versi baris dina indéks tina jinis naon waé. Nya, atanapi urang tiasa nganggap yén unggal garis diwakilan ku persis hiji versi. Dina basa sejen, teu aya widang xmin jeung xmax dina lulugu baris indéks. Urang bisa nganggap yén tumbu ti indéks ngakibatkeun sakabeh versi tabel baris - sangkan anjeun bisa angka kaluar nu versi urus bakal ningali ukur ku nempo tabél. (Salaku salawasna, ieu teu sakabeh bebeneran. Dina sababaraha kasus, peta pisibilitas bisa ngaoptimalkeun prosés, tapi urang bakal kasampak di ieu leuwih jéntré engké.)

Dina waktos anu sami, dina halaman indéks urang mendakan petunjuk pikeun duanana versi, boh anu ayeuna sareng anu lami:

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

Transaksi virtual

Dina prakna, PostgreSQL nganggo optimasi anu ngamungkinkeun pikeun "nyimpen" nomer transaksi.

Upami transaksi ngan ukur maca data, éta henteu gaduh pangaruh kana pisibilitas versi baris. Ku alatan éta, prosés jasa mimiti ngaluarkeun xid virtual pikeun transaksi. Jumlahna diwangun ku ID prosés sareng nomer sekuen.

Ngaluarkeun nomer ieu henteu ngabutuhkeun sinkronisasi antara sadaya prosés sahingga gancang pisan. Urang bakal kenal sareng alesan sanés pikeun ngagunakeun nomer virtual nalika urang ngobrol ngeunaan katirisan.

Nomer maya henteu dipertimbangkeun dina cara naon waé dina snapshot data.

Dina titik anu béda dina waktosna, tiasa waé aya transaksi virtual dina sistem kalayan nomer anu parantos dianggo, sareng ieu normal. Tapi nomer sapertos kitu teu tiasa diserat kana halaman data, sabab dina waktos salajengna halamanna diaksés, éta tiasa leungit sadayana hartosna.

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

Lamun urus mimiti ngarobah data, éta dibéré nyata, angka urus unik.

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

=> COMMIT;

Transaksi Nested

Simpen titik

Ditetepkeun dina SQL nyimpen titik (savepoint), nu ngidinan Anjeun pikeun ngabolaykeun bagian tina transaksi tanpa interrupting eta lengkep. Tapi ieu teu cocog kana diagram luhur, saprak urus boga status anu sarua pikeun sakabéh parobahanana, sarta fisik euweuh data digulung deui.

Pikeun nerapkeun fungsionalitas ieu, transaksi sareng savepoint dibagi jadi sababaraha misah transaksi nested (subtransaksi), statusna tiasa diurus nyalira.

transaksi Nested boga angka sorangan (leuwih luhur ti jumlah transaksi utama). Status transaksi nested dirékam dina cara biasa di XACT, tapi status final gumantung kana status tina transaksi utama: lamun eta dibatalkeun, teras sadaya transaksi nested ogé dibatalkeun.

Inpormasi ngeunaan nyarang transaksi disimpen dina file dina diréktori PGDATA/pg_subtrans. File diaksés ngaliwatan panyangga dina mémori anu dibagikeun dina conto, diatur dina cara anu sami sareng panyangga XACT.

Entong bingung transaksi nested sareng transaksi otonom. Transaksi otonom henteu gumantung ka silih dina cara naon waé, tapi transaksi nested. Henteu aya transaksi otonom dina PostgreSQL biasa, sareng, sigana, pikeun anu pangsaéna: aranjeunna diperyogikeun pisan, jarang pisan, sareng ayana dina DBMS anu sanés nyababkeun panyalahgunaan, ti mana sadayana sangsara.

Hayu urang mupus tabel, ngamimitian transaksi sareng selapkeun baris:

=> 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)

Ayeuna hayu urang nempatkeun titik simpen sareng selapkeun garis anu sanés.

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

Catet yén txid_current () fungsi mulih nomer urus utama, teu jumlah transaksi nested.

=> 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)

Hayu urang gulung deui ka titik simpen terus selapkeun garis katilu.

=> 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)

Dina kaca urang terus ningali baris ditambahkeun ku urus nested dibolaykeun.

Urang ngalereskeun parobahanana.

=> 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)

Ayeuna anjeun jelas tiasa ningali yén unggal transaksi nested gaduh status sorangan.

Catet yén transaksi nested teu tiasa dianggo sacara eksplisit dina SQL, nyaéta, anjeun moal tiasa ngamimitian transaksi énggal tanpa ngalengkepan anu ayeuna. Mékanisme ieu diaktipkeun sacara implisit nalika nganggo titik simpen, ogé nalika nanganan pengecualian PL/pgSQL sareng dina sababaraha kasus anu langkung aheng.

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

Kasalahan sareng atomicity operasi

Naon anu lumangsung upami aya kasalahan nalika ngalakukeun operasi? Contona, saperti kieu:

=> 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

Aya kasalahan. Ayeuna transaksi dianggap dibatalkeun sareng teu aya operasi anu diidinan:

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

Sareng upami anjeun nyobian ngalakukeun parobihan, PostgreSQL bakal ngalaporkeun abort:

=> COMMIT;
ROLLBACK

Naha transaksi henteu tiasa diteruskeun saatos gagal? Kanyataan yén kasalahan bisa timbul dina cara sapertos nu urang bakal meunang aksés ka bagian tina parobahan - atomicity malah teu urus, tapi operator bakal dilanggar. Saperti dina conto urang, dimana operator junun ngamutahirkeun hiji garis saméméh kasalahan:

=> 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)

Ieu kudu ngomong yén psql boga mode nu masih ngamungkinkeun urus neruskeun sanggeus gagalna saolah-olah lampah operator erroneous digulung deui.

=> 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;

Henteu hese nebak yén dina modeu ieu, psql leres-leres nempatkeun titik simpen implisit sateuacan unggal paréntah, sareng upami gagal ngamimitian ngabalikeun deui. Modeu ieu henteu dianggo sacara standar, sabab netepkeun titik panyimpen (sanaos henteu balik deui ka aranjeunna) ngalibatkeun overhead anu signifikan.

Tuluyan.

sumber: www.habr.com

Tambahkeun komentar