tableoid
是表对象的一个惟一标识符,能够和pg_class中的oid联合起来查看sql
xmin
是插入的事务标识符,是用来标识不一样事务下的一个版本控制数据库
xmax
是删除更新的事务标识符,若是该值不为0,则说明该行数据当前还未提交或回滚异步
cmin
插入事务的命令标识符,从0开始post
cmax
删除事务的命令标识符,或者为0版本控制
ctid
是每行数据在表中的一个物理位置标识符postgresql
下面举例说明:code
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 是插入数据的事务id xmax: 0 表示已经提交了 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) 从上面的数据能够看出当数据库作一个更新操做时,并非将老的数据删除,再将新的数据覆盖上去,相反它会把老的数据作一个标记隔离出去,而后再新增新的数据做为一个新的版本 如今看另外一个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) 从上面的数据逆推当Update时postgres 至少作三个动做 1. copy olddata to newplace 2. update data 3. add new transaction id to old data xmax postgresq Delete 会更简单一些只须要在tuple 上作一个标记. 既然postgres不会直接在olddata上修改,又是如何对这些tuple作隔离的呢? 简而言之postgres 如何判断这些tuple 是否对一个事务可见。 分析: 1. 对于tuple 的 xmin > 自身事务id 的row 必定是不可见 2. 对于tuple xmin < 自身事务id 的row而且已经提交的事务可见(deleted tuple 除外) 对于第一条规则很好判断(在自身事务以后的动做必定是看不见的)。 第二条规则困难一些须要判断一个事务是否提交,(可能还需判断tuple是不是deleted。由于postgresql vacuum 是异步删除deleted tuple) 对于这个问题postgres在tuple的header 里加入一个属性 t_infomask 用于标记transaction的状态.
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)