postgresql 的系統列 oid、tableoid、xmin、cmin、xmax、cmax、
oid
一行的物件識別符號(物件ID)。
該列只有在表使用WITH OIDS建立時或者default_with_oids配置變數被設定時才存在。
該列的型別為oid(與列名一致),該型別詳見第 8.18 節。
tableoid
包含這一行的表的OID。
該列是特別為從繼承層次(見第 5.9 節)中選擇的查詢而準備,因為如果沒有它將很難知道一行來自於哪個表。
tableoid可以與pg_class的oid列進行連線來獲得表的名稱。
xmin
插入該行版本的事務身份(事務ID)。
一個行版本是一個行的一個特別版本,對一個邏輯行的每一次更新都將建立一個新的行版本。
cmin
插入事務中的命令識別符號(從0開始)。
xmax
刪除事務的身份(事務ID),對於未刪除的行版本為0。
對於一個可見的行版本,該列值也可能為非零。
這通常表示刪除事務還沒有提交,或者一個刪除嘗試被回滾。
cmax
刪除事務中的命令識別符號,或者為0。
ctid
行版本在其表中的物理位置。
注意儘管ctid可以被用來非常快速地定位行版本,但是一個行的ctid會在被更新或者被VACUUM FULL移動時改變。
因此,ctid不能作為一個長期行識別符號。OID或者最好是一個使用者定義的序列號才應該被用來標識邏輯行。
初始化資料
postgres=# create table tmp_t0(c0 varchar(100),c1 varchar(100)); CREATE TABLE postgres=# insert into tmp_t0(c0,c1)values('1','1'); INSERT 0 1 postgres=# select tableoid,cmax,xmax,cmin,xmin,ctid,c0,c1,txid_current() from tmp_t0; tableoid | cmax | xmax | cmin | xmin | ctid | c0 | c1 | txid_current ----------+------+------+------+------+-------+----+----+-------------- 16393 | 0 | 0 | 0 | 1947 | (0,1) | 1 | 1 | 1948 (1 row) postgres=# insert into tmp_t0(c0,c1)values('2','2'); INSERT 0 1 postgres=# select tableoid,cmax,xmax,cmin,xmin,ctid,c0,c1,txid_current() from tmp_t0; tableoid | cmax | xmax | cmin | xmin | ctid | c0 | c1 | txid_current ----------+------+------+------+------+-------+----+----+-------------- 16393 | 0 | 0 | 0 | 1947 | (0,1) | 1 | 1 | 1950 16393 | 0 | 0 | 0 | 1949 | (0,2) | 2 | 2 | 1950 (2 rows) postgres=#
更新
session 1 操作
postgres=# begin; BEGIN postgres=# select tableoid,cmax,xmax,cmin,xmin,ctid,c0,c1,txid_current() from tmp_t0; tableoid | cmax | xmax | cmin | xmin | ctid | c0 | c1 | txid_current ----------+------+------+------+------+-------+----+----+-------------- 16393 | 0 | 0 | 0 | 1947 | (0,1) | 1 | 1 | 1951 16393 | 0 | 0 | 0 | 1949 | (0,2) | 2 | 2 | 1951 (2 rows) postgres=# update tmp_t0 set c1='11' where c0='1'; UPDATE 1 postgres=# select tableoid,cmax,xmax,cmin,xmin,ctid,c0,c1,txid_current() from tmp_t0; tableoid | cmax | xmax | cmin | xmin | ctid | c0 | c1 | txid_current ----------+------+------+------+------+-------+----+----+-------------- 16393 | 0 | 0 | 0 | 1949 | (0,2) | 2 | 2 | 1951 16393 | 0 | 0 | 0 | 1951 | (0,3) | 1 | 11 | 1951 (2 rows)
可以看到,update之後 c0='1’的ctid由(0,1)變為(0,3),同時xmin也發生了相應的變化。
此時在 session 1 裡不提交。
session 2 檢視
postgres=# select tableoid,cmax,xmax,cmin,xmin,ctid,c0,c1,txid_current() from tmp_t0;
tableoid | cmax | xmax | cmin | xmin | ctid | c0 | c1 | txid_current
----------+------+------+------+------+-------+----+----+--------------
16393 | 0 | 1951 | 0 | 1947 | (0,1) | 1 | 1 | 1953
16393 | 0 | 0 | 0 | 1949 | (0,2) | 2 | 2 | 1953
(2 rows)
顯示的c0='1’為update之前的值。postgresql 預設的事務隔離級別時 read committed,所以在session 2 是無法看到session 1已經更新,但是未提交的資料。
這個也側面驗證了 postgresql 的 mvcc 機制導致沒有在行原地 update,而是變為相應的 deleted 標籤和插入新行。