PostgreSQL基础 - 系统列(隐含字段)

oid

一行的对象标识符(对象ID)。
该列只有在表使用WITH OIDS创建时或者default_with_oids配置变量被设置时才存在。
该列的类型为oid(与列名一致)。

PostgreSQL号称是对象关系数据库,
relation就是class,
tuple/row 就是 object (class instance)

pg_class表也是relation, 它的每一行都是object, 所以它的每一行都有oid, 由于这个表的特殊性, 这个表的每一行的oid又有一个名称叫tableoid

tableoid

包含这一行的表的OID。
该列是特别为从继承层次(见第 5.9 节)中选择的查询而准备,因为如果没有它将很难知道一行来自于哪个表。
tableoid可以与pg_class的oid列进行连接来获得表的名称。

xmin

The identity (transaction ID) of the inserting transaction for this row version.
(A row version is an individual state of a row; each update of a row creates a new row
version for the same logical row.)

插入该行版本的事务号(事务ID)。
(由于MVCC机制, PostgreSQL目前的物理存储里没有修改操作, 只有标记删除+插入, 同一个逻辑行可以有多个版本, 多个物理行, 当然只有最新一个版本是有效的逻辑行)
一个行版本是一个逻辑行的历史版本,对一个逻辑行的每一次更新都将创建一个新的行版本。

xmax

The identity (transaction ID) of the deleting transaction, or zero for an undeleted
row version. It is possible for this column to be nonzero in a visible row version. That
usually indicates that the deleting transaction hasn it committed yet, or that an attempted
deletion was rolled back.

删除事务的身份(事务ID),对于未删除的行版本为0。
对于一个可见的行版本,该列值也可能为非零。这通常表示删除事务还没有提交,或者一个删除尝试被回滚。
(因为修改其实是标记删除+插入, 所以修改也是一个"删除事务")

xmin记录的是当数据插入( Insert )时的事务ID,xmax记录的是当行上的数据有变动(delete or update )时的事务ID
xmax==0: 行没有被改过
xmax!=0: 行被改过或者行修改失败

cmin (command min, 指同一个事务里执行的第几条SQL命令, 第一条是0)

插入事务中的命令标识符(从0开始)。

cmax (command max)

删除事务中的命令标识符,或者为0。
据网友看源码后得出的结论: cmin和cmax是同一个字段!!!它们两个的值永远都是相同的。

ctid

行版本在其表中的物理位置。
注意尽管ctid可以被用来非常快速地定位行版本,但是一个行的ctid会在被更新或者被VACUUM FULL移动时改变。
因此,ctid不能作为一个长期行标识符。OID或者最好是一个用户定义的序列号才应该被用来标识逻辑行。

物理行ID和逻辑行ID

实验

查询语句参考:

select 
    txid_current(), 
    tableoid as table_oid, tableoid::regclass::text as table_name, 
    ctid as physical_id, logical_id, 
    xmin as create_xid,xmax as modified_xid,
    cmin as sql_number, cmax  as sql_number_alias, 
    notes 
from system_column_test ;

下面正式开始实验:


-- 打开终端1, 进入psql执行

create table system_column_test (logical_id int primary key, notes text);
insert into system_column_test select generate_series(1,5);
select txid_current(), ctid, logical_id, xmin,xmax,cmin, cmax, notes from system_column_test ;

begin;
insert into system_column_test values(6);
insert into system_column_test values(7);
insert into system_column_test values(8);
commit;
select txid_current(), ctid, logical_id, xmin,xmax,cmin, cmax, notes from system_column_test ;

begin;
insert into system_column_test values(9);
insert into system_column_test values(10);
commit;
select txid_current(), ctid, logical_id, xmin,xmax,cmin, cmax, notes from system_column_test ;

-- 可以看到, xmax 值都是为0,xmin则有3个(1~5相同, 6~8相同, 9~10相同)
-- 那什么情况下 xmax 值不为0呢,有几种情况,接下来看

-- 1. deleting事务未提交
-- 1.1 开启终端2, 进入psql执行
begin;
select txid_current();
delete from system_column_test where logical_id=3;
-- 1.2 切换到终端1
select xmin,xmax,ctid,* from system_column_test;
-- 可以看到logical_id=3的记录的 xmax 变为 非0了。
-- 1.3 切换到终端2
commit;
-- 1.4 切换到终端1
select xmin,xmax,ctid,* from system_column_test;
-- logical_id=3的记录已经被删除

-- 2. delete 事务 rollback
begin;
select txid_current();  
delete from system_column_test where logical_id=4;
rollback;
select xmin,xmax,ctid,* from system_column_test;
-- 可以看到logical_id=4的记录的 xmax 变为 非0了。
-- 注意: ctid没有发生变化

-- 3. updating 事务 rollback
begin;
select txid_current();
update system_column_test set  notes = 'updated' where logical_id=5;
rollback;
select xmin,xmax,ctid,* from system_column_test;
-- 可以看到logical_id=5的记录的 xmax 变为 非0了。
-- 同时, ctid同样没有发生变化
-- 用pageinspect插件查看物理页看看页面情况。
select * from heap_page_items(get_raw_page('system_column_test',0)) order by lp_off desc;
-- 用pageinspect看到的ctid却是变化了的...

-- 4. update 事务 commit
-- 注意: 这个不是xmax 值不为0的情况, 但是有参考意义, 所以一同列出来
begin;
select txid_current();
update system_column_test set  notes = 'updated' where logical_id=2;
commit;
select xmin,xmax,ctid,* from system_column_test;
-- 可以看到logical_id=2的记录的 xmax 还是 0。
-- 不过, ctid发生变化
-- 用pageinspect插件查看物理页看看页面情况。
select * from heap_page_items(get_raw_page('system_column_test',0)) order by lp_off desc;
-- 用pageinspect看到总共有12行, 10个有效行, 2个dead行

操作过程中的输出就不贴了, 只贴出最终结果:


postgres=# select xmin,xmax,ctid,* from system_column_test;
 xmin | xmax |  ctid  | logical_id |  notes
------+------+--------+------------+---------
  898 |    0 | (0,1)  |          1 |
  898 |  905 | (0,4)  |          4 |
  898 |  906 | (0,5)  |          5 |
  900 |    0 | (0,6)  |          6 |
  900 |    0 | (0,7)  |          7 |
  900 |    0 | (0,8)  |          8 |
  902 |    0 | (0,9)  |          9 |
  902 |    0 | (0,10) |         10 |
  907 |    0 | (0,12) |          2 | updated
(9 rows)

postgres=# select lp,lp_off,t_xmin, t_xmax, t_field3 as cmin_cmax, t_ctid, t_infomask, t_infomask2,t_data from heap_page_items(get_raw_page('system_column_test',0)) order by lp_off desc;
 lp | lp_off | t_xmin | t_xmax | cmin_cmax | t_ctid | t_infomask | t_infomask2 |           t_data
----+--------+--------+--------+-----------+--------+------------+-------------+----------------------------
  1 |   8160 |    898 |      0 |         0 | (0,1)  |       2305 |           2 | \x01000000
  2 |   8128 |    898 |    907 |         0 | (0,12) |       1281 |       16386 | \x02000000
  3 |   8096 |    898 |    904 |         0 | (0,3)  |       1281 |        8194 | \x03000000
  4 |   8064 |    898 |    905 |         0 | (0,4)  |       2305 |        8194 | \x04000000
  5 |   8032 |    898 |    906 |         0 | (0,11) |       2305 |       16386 | \x05000000
  6 |   8000 |    900 |      0 |         0 | (0,6)  |       2305 |           2 | \x06000000
  7 |   7968 |    900 |      0 |         1 | (0,7)  |       2305 |           2 | \x07000000
  8 |   7936 |    900 |      0 |         2 | (0,8)  |       2305 |           2 | \x08000000
  9 |   7904 |    902 |      0 |         0 | (0,9)  |       2305 |           2 | \x09000000
 10 |   7872 |    902 |      0 |         1 | (0,10) |       2305 |           2 | \x0a000000
 11 |   7832 |    906 |      0 |         0 | (0,11) |      10754 |       32770 | \x050000001175706461746564
 12 |   7792 |    907 |      0 |         0 | (0,12) |      10498 |       32770 | \x020000001175706461746564
(12 rows)

参考文档:

  1. 官方文档-系统列
  2. postgresql 的系统列 oid、tableoid、xmin、cmin、xmax、cmax
  3. 表级隐含字段: Xmin 和 Xmax
  4. postgresql里cmin与cmax有何不同.md

你可能感兴趣的:(PostgreSQL基础 - 系统列(隐含字段))