PostgreSQL 数据库中的表,有几个字段是系统字段,这些字段是隐藏的,在 psql 中使用 \d 命令不会显示这些字段。用户在定义表结构时,字段名称不能与这些系统隐藏字段相同。
隐藏字段如下:
- oid,行对象标识符,这个字段只有在创建表时使用了 with oids 或者配置参数 default_with_oids 为真时,才会出现。
- tableoid,包含当前行的表 oid。
- xmin,插入该行版本的事务ID。
- xmax,删除此行的事务ID,第一次插入时,该字段为 0
- cmin,事务内部插入类操作的命令 ID,此标识是从 0 开始的。
- cmax,事务内部删除类操作的命令ID,如果不是删除命令,此字段为 0 。
- ctid,一个行版本在它所处的表内的物理位置。
oid:
PostgreSQL 内部使用的标识符,用来作为系统表的主键。用户创建的表默认不带 oid 字段,如果用户在创建表时指定 with oids 子句,则用户表也会包含 oid 字段。oid 类型为 4 字节无符号整数,oid 的序列值是全局的,也就是所有表共享 oid 序列,因此它提供的数值范围有限,PostgreSQL 官方不建议用户表带有 oid 字段。
ctid:
表示数据行在其所处的表中的物理位置,ctid 类型为 tid,ctid 可以快速地定位数据行,但是 vacuum full 之后,数据行的物理位置会变动,导致其 ctid 发生变化,不能使用 ctid 作为长期的行数据的标识,应该使用主键来标识一个逻辑行数据。
PostgreSQL 支持查询 ctid 值,以及按 ctid 来查询记录,示例如下:
pg=# select ctid,id,name from tb;
ctid | id | name
-------+----+------
(0,1) | 1 | abc
(0,2) | 2 | efg
(2 rows)
pg=# select ctid,id,name from tb where ctid='(0,2)';
ctid | id | name
-------+----+------
(0,2) | 2 | efg
(1 row)
ctid 由两个数字组成,第一个数字表示物理块号,第二个数字表示在物理块号中的行号。
xmin & xmax & cmin & cmax:
这四个字段在多版本控制中,用于控制数据行是否对用户可见。
- 当插入一行时,该行的 xmin 设置为当前事务的事务 ID,xmax 设置为 0 。
- 修改某一行时,实际上是新插入一行,旧行的 xmin 不变,旧行的 xmax 设置为当前事务的事务 ID,新行的 xmin 设置为当前事务的事务 ID,新行的 xmax 设置为 0。
- 删除某一行时,被删除行的 xmax 设置为当前事务的事务 ID。
cmin 和 cmax 用于判断同一个事务内,不同命令导致的行版本变化是否可见。PostgreSQL 引入了命令 ID 的概念,行上记录了操作该行的命令 ID,当其他命令读取这行时,如果当前的命令 ID 大于等于 数据行上的命令 ID,则该行数据是可见的,否则不可见,其使用与 xmin 和 xmax 类似。