摘要:分析對于的自身事務(wù)的一定是不可見對于自身事務(wù)的并且已經(jīng)提交的事務(wù)可見除外對于第一條規(guī)則很好判斷在自身事務(wù)之后的動作一定是看不見的。第二條規(guī)則困難一些需要判斷一個事務(wù)是否提交可能還需判斷是否是。
Postgresql MVCC Postgresql的隱藏列
tableoid
是表對象的一個唯一標(biāo)識符,可以和pg_class中的oid聯(lián)合起來查看
xmin
是插入的事務(wù)標(biāo)識符,是用來標(biāo)識不同事務(wù)下的一個版本控制
xmax
是刪除更新的事務(wù)標(biāo)識符,如果該值不為0,則說明該行數(shù)據(jù)當(dāng)前還未提交或回滾
cmin
插入事務(wù)的命令標(biāo)識符,從0開始
cmax
刪除事務(wù)的命令標(biāo)識符,或者為0
ctid
是每行數(shù)據(jù)在表中的一個物理位置標(biāo)識符
下面舉例說明:
t1=# create table test (id integer, value text); CREATE TABLE t1=# insert into test values (1, "a"), (2, "aa"), (3, "aaa"); INSERT 0 3 t1=# select cmin,cmax,xmin,xmax,ctid, * from test; cmin | cmax | xmin | xmax | ctid | id | value ------+------+----------+------+-------+----+------- 0 | 0 | 75066031 | 0 | (0,1) | 1 | a 0 | 0 | 75066031 | 0 | (0,2) | 2 | aa 0 | 0 | 75066031 | 0 | (0,3) | 3 | aaa (3 rows) xmin: 75066031 是插入數(shù)據(jù)的事務(wù)id xmax: 0 表示已經(jīng)提交了 ctid: (0, 1), (0, 2), (0, 3)是tuple 所在table中的位置 t1=# begin; BEGIN t1=# select tableoid from test; tableoid ---------- 96972 96972 96972 (3 rows) t1=# insert into test values (4, "b"); INSERT 0 1 t1=# insert into test values (5, "bb"); INSERT 0 1 t1=# insert into test values (6, "bbb"); INSERT 0 1 t1=# select cmin,cmax,xmin,xmax,ctid, * from test; cmin | cmax | xmin | xmax | ctid | id | value ------+------+----------+------+-------+----+------- 0 | 0 | 75066031 | 0 | (0,1) | 1 | a 0 | 0 | 75066031 | 0 | (0,2) | 2 | aa 0 | 0 | 75066031 | 0 | (0,3) | 3 | aaa 0 | 0 | 75066040 | 0 | (0,4) | 4 | b 1 | 1 | 75066040 | 0 | (0,5) | 5 | bb 2 | 2 | 75066040 | 0 | (0,6) | 6 | bbb (6 rows) t1=# commit; COMMIT tableoid: 是表的oid
首先打開兩個psql t1=# begin; BEGIN t1=# select cmin,cmax,xmin,xmax,ctid, * from test; cmin | cmax | xmin | xmax | ctid | id | value ------+------+----------+------+-------+----+------- 0 | 0 | 75066031 | 0 | (0,1) | 1 | a 0 | 0 | 75066031 | 0 | (0,2) | 2 | aa 0 | 0 | 75066031 | 0 | (0,3) | 3 | aaa 0 | 0 | 75066040 | 0 | (0,4) | 4 | b 1 | 1 | 75066040 | 0 | (0,5) | 5 | bb 2 | 2 | 75066040 | 0 | (0,6) | 6 | bbb (6 rows) t1=# update test set value = "c" where id = 4; UPDATE 1 t1=# select cmin,cmax,xmin,xmax,ctid, * from test; cmin | cmax | xmin | xmax | ctid | id | value ------+------+----------+------+-------+----+------- 0 | 0 | 75066031 | 0 | (0,1) | 1 | a 0 | 0 | 75066031 | 0 | (0,2) | 2 | aa 0 | 0 | 75066031 | 0 | (0,3) | 3 | aaa 1 | 1 | 75066040 | 0 | (0,5) | 5 | bb 2 | 2 | 75066040 | 0 | (0,6) | 6 | bbb 0 | 0 | 75066045 | 0 | (0,7) | 4 | c (6 rows) t1=# select txid_current(); txid_current -------------- 75066045 (1 row) 從上面的數(shù)據(jù)可以看出當(dāng)數(shù)據(jù)庫做一個更新操作時,并不是將老的數(shù)據(jù)刪除,再將新的數(shù)據(jù)覆蓋上去,相反它會把老的數(shù)據(jù)做一個標(biāo)記隔離出去,然后再新增新的數(shù)據(jù)作為一個新的版本 現(xiàn)在看另一個psql t1=# begin; BEGIN t1=# select cmin,cmax,xmin,xmax,ctid, * from test; cmin | cmax | xmin | xmax | ctid | id | value ------+------+----------+----------+-------+----+------- 0 | 0 | 75066031 | 0 | (0,1) | 1 | a 0 | 0 | 75066031 | 0 | (0,2) | 2 | aa 0 | 0 | 75066031 | 0 | (0,3) | 3 | aaa 0 | 0 | 75066040 | 75066045 | (0,4) | 4 | b 1 | 1 | 75066040 | 0 | (0,5) | 5 | bb 2 | 2 | 75066040 | 0 | (0,6) | 6 | bbb (6 rows) 從上面的數(shù)據(jù)逆推當(dāng)Update時postgres 至少做三個動作 1. copy olddata to newplace 2. update data 3. add new transaction id to old data xmax postgresq Delete 會更簡單一些只需要在tuple 上做一個標(biāo)記. 既然postgres不會直接在olddata上修改,又是如何對這些tuple做隔離的呢? 簡而言之postgres 如何判斷這些tuple 是否對一個事務(wù)可見。 分析: 1. 對于tuple 的 xmin > 自身事務(wù)id 的row 一定是不可見 2. 對于tuple xmin < 自身事務(wù)id 的row并且已經(jīng)提交的事務(wù)可見(deleted tuple 除外) 對于第一條規(guī)則很好判斷(在自身事務(wù)之后的動作一定是看不見的)。 第二條規(guī)則困難一些需要判斷一個事務(wù)是否提交,(可能還需判斷tuple是否是deleted。因?yàn)閜ostgresql vacuum 是異步刪除deleted tuple) 對于這個問題postgres在tuple的header 里加入一個屬性 t_infomask 用于標(biāo)記transaction的狀態(tài).
select * from pg_available_extensions; create extension pageinspect; t1=# begin; BEGIN t1=# select cmin,cmax,xmin,xmax,ctid, * from test; cmin | cmax | xmin | xmax | ctid | id | value ------+------+----------+------+-------+----+------- 0 | 0 | 75066031 | 0 | (0,1) | 1 | a 0 | 0 | 75066031 | 0 | (0,2) | 2 | aa 0 | 0 | 75066031 | 0 | (0,3) | 3 | aaa 1 | 1 | 75066040 | 0 | (0,4) | 5 | bb 2 | 2 | 75066040 | 0 | (0,5) | 6 | bbb 0 | 0 | 75066110 | 0 | (0,6) | 4 | b (6 rows) t1=# SELECT * FROM heap_page_items(get_raw_page("test", 0)); lp | lp_off | lp_flags | lp_len | t_xmin | t_xmax | t_field3 | t_ctid | t_infomask2 | t_infomask | t_hoff | t_bits | t_oid ----+--------+----------+--------+----------+--------+----------+--------+-------------+------------+--------+--------+------- 1 | 8160 | 1 | 30 | 75066031 | 0 | 0 | (0,1) | 2 | 2818 | 24 | | 2 | 8128 | 1 | 31 | 75066031 | 0 | 0 | (0,2) | 2 | 2818 | 24 | | 3 | 8096 | 1 | 32 | 75066031 | 0 | 0 | (0,3) | 2 | 2818 | 24 | | 4 | 8064 | 1 | 31 | 75066040 | 0 | 1 | (0,4) | 2 | 2818 | 24 | | 5 | 8032 | 1 | 32 | 75066040 | 0 | 2 | (0,5) | 2 | 2818 | 24 | | 6 | 8000 | 1 | 30 | 75066110 | 0 | 0 | (0,6) | 2 | 11010 | 24 | | (6 rows) t1=# update test set value = "c" where id = 4; UPDATE 1 t1=# SELECT * FROM heap_page_items(get_raw_page("test", 0)); lp | lp_off | lp_flags | lp_len | t_xmin | t_xmax | t_field3 | t_ctid | t_infomask2 | t_infomask | t_hoff | t_bits | t_oid ----+--------+----------+--------+----------+----------+----------+--------+-------------+------------+--------+--------+------- 1 | 8160 | 1 | 30 | 75066031 | 0 | 0 | (0,1) | 2 | 2818 | 24 | | 2 | 8128 | 1 | 31 | 75066031 | 0 | 0 | (0,2) | 2 | 2818 | 24 | | 3 | 8096 | 1 | 32 | 75066031 | 0 | 0 | (0,3) | 2 | 2818 | 24 | | 4 | 8064 | 1 | 31 | 75066040 | 0 | 1 | (0,4) | 2 | 2818 | 24 | | 5 | 8032 | 1 | 32 | 75066040 | 0 | 2 | (0,5) | 2 | 2818 | 24 | | 6 | 8000 | 1 | 30 | 75066110 | 75066121 | 0 | (0,7) | 16386 | 8962 | 24 | | 7 | 7968 | 1 | 30 | 75066121 | 0 | 0 | (0,7) | 32770 | 10242 | 24 | | (7 rows) t1=# select cmin,cmax,xmin,xmax,ctid, * from test; cmin | cmax | xmin | xmax | ctid | id | value ------+------+----------+------+-------+----+------- 0 | 0 | 75066031 | 0 | (0,1) | 1 | a 0 | 0 | 75066031 | 0 | (0,2) | 2 | aa 0 | 0 | 75066031 | 0 | (0,3) | 3 | aaa 1 | 1 | 75066040 | 0 | (0,4) | 5 | bb 2 | 2 | 75066040 | 0 | (0,5) | 6 | bbb 0 | 0 | 75066121 | 0 | (0,7) | 4 | c (6 rows) t1=# select txid_current(); txid_current -------------- 75066121 (1 row)
Vacuum internals 文章實(shí)在太好了
Postgres Hint Bits
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/38954.html
摘要:關(guān)系型數(shù)據(jù)庫中的事務(wù)管理詳解并發(fā)控制與事務(wù)日志數(shù)據(jù)庫系統(tǒng)的萌芽出現(xiàn)于年代。并發(fā)控制并發(fā)控制旨在針對數(shù)據(jù)庫中對事務(wù)并行的場景,保證中的一致性與隔離性。絕大部分?jǐn)?shù)據(jù)庫會采用鎖或者數(shù)據(jù)版本控制的方式來處理并發(fā)控制問題。 本文節(jié)選自:關(guān)系型數(shù)據(jù)庫理論 https://url.wx-coder.cn/DJNQn ,涉及引用/整理的文章列舉在了 Database-List。 showImg(htt...
摘要:關(guān)系型數(shù)據(jù)庫中的事務(wù)管理詳解并發(fā)控制與事務(wù)日志數(shù)據(jù)庫系統(tǒng)的萌芽出現(xiàn)于年代。并發(fā)控制并發(fā)控制旨在針對數(shù)據(jù)庫中對事務(wù)并行的場景,保證中的一致性與隔離性。絕大部分?jǐn)?shù)據(jù)庫會采用鎖或者數(shù)據(jù)版本控制的方式來處理并發(fā)控制問題。 本文節(jié)選自:關(guān)系型數(shù)據(jù)庫理論 https://url.wx-coder.cn/DJNQn ,涉及引用/整理的文章列舉在了 Database-List。 showImg(htt...
閱讀 7242·2021-09-22 15:36
閱讀 6037·2021-09-02 10:20
閱讀 1935·2019-08-30 15:44
閱讀 2723·2019-08-29 14:06
閱讀 1216·2019-08-29 11:17
閱讀 1670·2019-08-26 14:05
閱讀 3234·2019-08-26 13:50
閱讀 1618·2019-08-26 10:26