PostgreSQL基礎(chǔ) - 系統(tǒng)列(隱含字段)

oid

一行的對(duì)象標(biāo)識(shí)符(對(duì)象ID)。
該列只有在表使用WITH OIDS創(chuàng)建時(shí)或者default_with_oids配置變量被設(shè)置時(shí)才存在。
該列的類型為oid(與列名一致)。

PostgreSQL號(hào)稱是對(duì)象關(guān)系數(shù)據(jù)庫,
relation就是class,
tuple/row 就是 object (class instance)

pg_class表也是relation, 它的每一行都是object, 所以它的每一行都有oid, 由于這個(gè)表的特殊性, 這個(gè)表的每一行的oid又有一個(gè)名稱叫tableoid

tableoid

包含這一行的表的OID。
該列是特別為從繼承層次(見第 5.9 節(jié))中選擇的查詢而準(zhǔn)備,因?yàn)槿绻麤]有它將很難知道一行來自于哪個(gè)表。
tableoid可以與pg_class的oid列進(jìn)行連接來獲得表的名稱。

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.)

插入該行版本的事務(wù)號(hào)(事務(wù)ID)。
(由于MVCC機(jī)制, PostgreSQL目前的物理存儲(chǔ)里沒有修改操作, 只有標(biāo)記刪除+插入, 同一個(gè)邏輯行可以有多個(gè)版本, 多個(gè)物理行, 當(dāng)然只有最新一個(gè)版本是有效的邏輯行)
一個(gè)行版本是一個(gè)邏輯行的歷史版本,對(duì)一個(gè)邏輯行的每一次更新都將創(chuàng)建一個(gè)新的行版本。

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.

刪除事務(wù)的身份(事務(wù)ID),對(duì)于未刪除的行版本為0。
對(duì)于一個(gè)可見的行版本,該列值也可能為非零。這通常表示刪除事務(wù)還沒有提交,或者一個(gè)刪除嘗試被回滾。
(因?yàn)樾薷钠鋵?shí)是標(biāo)記刪除+插入, 所以修改也是一個(gè)"刪除事務(wù)")

xmin記錄的是當(dāng)數(shù)據(jù)插入( Insert )時(shí)的事務(wù)ID,xmax記錄的是當(dāng)行上的數(shù)據(jù)有變動(dòng)(delete or update )時(shí)的事務(wù)ID
xmax==0: 行沒有被改過
xmax!=0: 行被改過或者行修改失敗

cmin (command min, 指同一個(gè)事務(wù)里執(zhí)行的第幾條SQL命令, 第一條是0)

插入事務(wù)中的命令標(biāo)識(shí)符(從0開始)。

cmax (command max)

刪除事務(wù)中的命令標(biāo)識(shí)符,或者為0。
據(jù)網(wǎng)友看源碼后得出的結(jié)論: cmin和cmax是同一個(gè)字段!!!它們兩個(gè)的值永遠(yuǎn)都是相同的。

ctid

行版本在其表中的物理位置。
注意盡管ctid可以被用來非??焖俚囟ㄎ恍邪姹?,但是一個(gè)行的ctid會(huì)在被更新或者被VACUUM FULL移動(dòng)時(shí)改變。
因此,ctid不能作為一個(gè)長(zhǎng)期行標(biāo)識(shí)符。OID或者最好是一個(gè)用戶定義的序列號(hào)才應(yīng)該被用來標(biāo)識(shí)邏輯行。

物理行ID和邏輯行ID

實(shí)驗(yàn)

查詢語句參考:

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 ;

下面正式開始實(shí)驗(yàn):


-- 打開終端1, 進(jìn)入psql執(zhí)行

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個(gè)(1~5相同, 6~8相同, 9~10相同)
-- 那什么情況下 xmax 值不為0呢,有幾種情況,接下來看

-- 1. deleting事務(wù)未提交
-- 1.1 開啟終端2, 進(jìn)入psql執(zhí)行
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 變?yōu)?非0了。
-- 1.3 切換到終端2
commit;
-- 1.4 切換到終端1
select xmin,xmax,ctid,* from system_column_test;
-- logical_id=3的記錄已經(jīng)被刪除

-- 2. delete 事務(wù) 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 變?yōu)?非0了。
-- 注意: ctid沒有發(fā)生變化

-- 3. updating 事務(wù) 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 變?yōu)?非0了。
-- 同時(shí), ctid同樣沒有發(fā)生變化
-- 用pageinspect插件查看物理頁看看頁面情況。
select * from heap_page_items(get_raw_page('system_column_test',0)) order by lp_off desc;
-- 用pageinspect看到的ctid卻是變化了的...

-- 4. update 事務(wù) commit
-- 注意: 這個(gè)不是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發(fā)生變化
-- 用pageinspect插件查看物理頁看看頁面情況。
select * from heap_page_items(get_raw_page('system_column_test',0)) order by lp_off desc;
-- 用pageinspect看到總共有12行, 10個(gè)有效行, 2個(gè)dead行

操作過程中的輸出就不貼了, 只貼出最終結(jié)果:


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. 官方文檔-系統(tǒng)列
  2. postgresql 的系統(tǒng)列 oid、tableoid、xmin、cmin、xmax、cmax
  3. 表級(jí)隱含字段: Xmin 和 Xmax
  4. postgresql里cmin與cmax有何不同.md
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容