隐藏字段xmin/xmax/cmin/cmax
xmin和xmax
-
创建insert:
- xmin填 当前事务ID
- xmax填 0
-
更新update:
- 实际分两步,相当于操作了两行
- 第一步
delete旧行- xmin 不变
- xmax填 当前事务ID
- 第二步
insert新行- xmin填 当前事务ID
- xmax填 0
- 第一步
- 实际分两步,相当于操作了两行
-
删除delete:
- xmin 不变
- xmax填 当前事务ID
-
总结
- 填充的都是 事务ID
- 创建的时候,会填到xmin里,而xmax默认为0
- 删除的时候,会填到xmax里,而xmin不变
- 填充的都是 事务ID
-
用途
-
判断upsert的时候,到底是 insert 还是 update
INSERT INTO test VALUES (1, 2, 3) ON CONFLICT ( id ) DO UPDATE SET a = 5,b = 6 RETURING id, ( CASE WHEN xmax <> 0 THEN 'UPDATE' ELSE 'INSERT' END ) AS type; -
解释
- 如果xmax为0,则代表,是纯粹的创建
- 如果xmax不为0,则代表删除过,反映的是旧行
-
注意:这个不能用于update,因为纯粹的更新,反映的是新行上的xmax仍为0,而不是旧行上xmax为事务号
-
如果不用隐藏字段,就需要用下面更麻烦的方式判断
WITH tt AS (SELECT 1 AS abc FROM test WHERE id = 1) INSERT INTO test VALUES (1, 2, 3) ON CONFLICT (id) DO UPDATE SET a = 5, b = 6 RETURNING ( SELECT abc FROM tt );- 这里用到了
WITH和RETURNING- 返回Null代表查不到,是insert
- 返回1代表查到,是update
- 这里用到了
-
cmin和cmax
-
事务内的顺序号,值基本一样,貌似是同一个东西
-
如果
- 一个事务只执行一个insert
- 那么,值为0
- 一个事务执行了两个insert
- 那么,一个是0,一个是1
- 代表了事务内执行的顺序
- 一个事务只执行一个update
- 那么,值变成了1
- 一个事务只执行一个insert
ctid
-
代表了 数据行 在表中的
物理位置 -
由一对数值组成(块编号和行索引),可以快速找到数据行
-
注意:
- ctid 的值有可能会改变
- 比如发生在
VACUUM FULL - 所以不适合作为长期的行标识,而是要用主键
tableid
-
代表了 表 的对象id
-
会出现在pg_class数字字典表中
SELECT oid, relname FROM pg_class WHERE relname = 'test';