postgresql隐藏字段 ctid xmin xmax cmin cmax oid

postgresql隐藏字段
在 PostgreSQL 中,当我们创建一个数据表时,数据库会隐式增加几个字段。这些字段由数据库系自动维护,用户一般不会感知
tableoid
ctid
xmin
xmax
cmin
cmax
oid

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

xmin
插入该行版本的事务身份(事务ID)。一个行版本是一个行的一个特别版本,对一个逻辑行的每一次更新都将创建一个新的行版本。

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

xmax
删除事务的身份(事务ID),对于未删除的行版本为0。对于一个可见的行版本,该列值也可能为非零。这通常表示删除事务还没有提交,或者一个删除尝试被回滚。

cmax
删除事务中的命令标识符,或者为0。

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

select attname, attnum, atttypid::regtype from pg_attribute where attrelid = 'test_abc'::regclass; //::双冒号表示类型转换,即将atttypid字段转换为regtype类型数据 regclass表示OID的别名 // pg_attribute该系统表存储所有表(包括系统表,如pg_class)的字段信息。数据库中的每个表的每个字段在pg_attribute表中都有一行记录。 attname 字段名 atttypid 字段的数据类型。attnum 字段的编号,普通字段是从1开始计数的。系统字段,如oid,是任意的负数。

select t.tableoid, t.id,t.name, c.relname from test_abc t join pg_class c on (c.oid = t.tableoid);

ctid表示数据行的在它所处的表内的物理位置。ctid字段的类型是是tid。尽管tid可以非常快的定位数据行。但是每次vacuum full之后。数据行在块内的物理位置会移动。即ctid会发生变化。所以ctid不能长期作为行标识符,ctid由两个数字组成,第一个数字表示物理块号,第二个数字表示在物理块中的行数
xmin 代表了该行版本(row version )的插入事务 ID(XID)。行版本是数据行的具体状态,每次更新操作都会为相同的逻辑行创建一个新的行版本

mydb=# create table test_abc(id int,name varchar(20));
CREATE TABLE
mydb=# \d+ test_abc;
                                         Table "public.test_abc"
 Column |         Type          | Collation | Nullable | Default | Storage  | Stats target | Description
--------+-----------------------+-----------+----------+---------+----------+--------------+-------------
 id     | integer               |           |          |         | plain    |              |
 name   | character varying(20) |           |          |         | extended |              |

mydb=# insert into test_abc values(1,'aaa'),(2,'bbb'),(3,'ccc');
INSERT 0 3
mydb=# select * from test_abc;l
 id | name
----+------
  1 | aaa
  2 | bbb
  3 | ccc
  mydb=# select id,name,ctid,xmin,xmax,cmax,cmin from test_abc;
 id | name | ctid  | xmin | xmax | cmax | cmin
----+------+-------+------+------+------+------
  1 | aaa  | (0,1) |  641 |    0 |    0 |    0
  2 | bbb  | (0,2) |  641 |    0 |    0 |    0
  3 | ccc  | (0,3) |  641 |    0 |    0 |    0

xmin 字段可以用于查看数据行的插入时间:
select id,name,to_char(pg_xact_commit_timestamp(xmin) ,'YYYY-MM-DD HH24:MI:SS') AS insert_time from test_abc;
记录transaction的提交时间。
注意:只有当"track_commit_timestamp"参数是on时,函数pg_xact_commit_timestamp(xid)、pg_last_committed_xact()才能获得已提交事务的时间值。该参数需要重启

xmax 字段代表了删除改行的事务 ID,对于未删除的行版本显示为 0。非零的 xmax 通常意味着删除事务还没有提交,或者删除操作被回滚。

查看当前事务ID

select txid_current();
 txid_current
--------------
          645
(1 row)

mydb=# select id,name,ctid,xmin,xmax,cmax,cmin from test_abc;
 id | name | ctid  | xmin | xmax | cmax | cmin
----+------+-------+------+------+------+------
  1 | aaa  | (0,1) |  641 |    0 |    0 |    0
  2 | bbb  | (0,2) |  641 |    0 |    0 |    0
  3 | ccc  | (0,3) |  641 |    0 |    0 |    0
  4 | ddd  | (0,4) |  642 |    0 |    0 |    0
mydb=# update test_abc set name='ddd' where id=1;
UPDATE 1
mydb=# select * from test_abc;
 id | name
----+------
  2 | bbb
  3 | ccc
  4 | ddd
  1 | ddd
(4 rows)

mydb=# select id,name,ctid,xmin,xmax,cmax,cmin from test_abc;
 id | name | ctid  | xmin | xmax | cmax | cmin
----+------+-------+------+------+------+------
  2 | bbb  | (0,2) |  641 |    0 |    0 |    0
  3 | ccc  | (0,3) |  641 |    0 |    0 |    0
  4 | ddd  | (0,4) |  642 |    0 |    0 |    0
  1 | ddd  | (0,5) |  645 |    0 |    0 |    0
ctid以改变成(0,5)

从当前事务中已经看不到aaa那条记录,但是1,ddd这条被修改后的xmin为645为当前的事务ID,
从事务2的窗口查看

mydb=# begin;
BEGIN
mydb=# select txid_current();
 txid_current
--------------
          646
(1 row)

mydb=#  select id,name,ctid,xmin,xmax,cmax,cmin
 id | name | ctid  | xmin | xmax | cmax | cmin
----+------+-------+------+------+------+------
  1 | aaa  | (0,1) |  641 |  645 |    0 |    0
  2 | bbb  | (0,2) |  641 |    0 |    0 |    0
  3 | ccc  | (0,3) |  641 |    0 |    0 |    0
  4 | ddd  | (0,4) |  642 |    0 |    0 |    0

aaa的记录xmin为641是该条记录插入式的事务id,xmax为该条记录删除的事务ID,即事务1的事务ID,也就是说update在pg中处理为删除老的记录,在插入一条新的记录,删除老的记录时,老的记录的xmax被改成删除操作所在的事务ID
在同一事务中,如果不通数据记录的xmax>xmin,则说明xmax的数据在xmin数据之后

posted @ 2022-06-20 17:06  南大仙  阅读(1161)  评论(0编辑  收藏  举报