1. 程式人生 > >postgresql 的系統列 oid、tableoid、xmin、cmin、xmax、cmax、

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 標籤和插入新行。

參考:
http://postgres.cn/docs/9.6/ddl-system-columns.html