文章目录

  • tableoid
  • ctid
  • xmin
  • xmax
  • cmin
  • cmax
  • oid
  • 总结

大家好!我是只谈技术不剪发的 Tony 老师。今天我们来谈谈 PostgreSQL 数据表中几个隐藏的系统字段和它们的作用。

在 PostgreSQL 中,当我们创建一个数据表时,数据库会隐式增加几个系统字段。这些字段由系统进行维护,用户一般不会感知它们的存在。例如,以下语句创建了一个简单的表:

create table test(col integer);insert into test(col)
values (1),(2),(3);

从定义上来看,表 test 中只有一个字段;但是当我们查询数据字典表 pg_attribute 时,结果却不是如此:

hrdb=> select version();version
---------------------------------------------------------------------------------------------------------PostgreSQL 12.3 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39), 64-bit
(1 row)hrdb=> select attname, attnum, atttypid::regtype
hrdb-> from pg_attribute
hrdb-> where attrelid = 'test'::regclass;attname  | attnum | atttypid
----------+--------+----------tableoid |     -6 | oidcmax     |     -5 | cidxmax     |     -4 | xidcmin     |     -3 | cidxmin     |     -2 | xidctid     |     -1 | tidcol      |      1 | integer
(7 rows)

查询结果显示,表 test 中一共包含 7 个字段。PostgreSQL 为我们增加了 6 个额外的系统字段,它们的 attnum 属性都是负数。

下面让我们分别看看这些系统字段的作用。

tableoid

tableoid 字段代表了数据所在表的对象 id(OID),也就是数据字典表 pg_class 中与该表信息相关的数据行。

hrdb=> select oid, relname from pg_class where relname = 'test';oid  | relname
-------+---------90277 | test
(1 row)hrdb=> select t.tableoid, t.col, c.relname
hrdb-> from test t
hrdb-> join pg_class c on (c.oid = t.tableoid);tableoid | col | relname
----------+-----+---------90277 |   1 | test90277 |   2 | test90277 |   3 | test
(3 rows)

tableoid 的另一个用途就是在涉及分区表查询或者 UNION 操作时标识数据行所在的具体表。例如存在以下分区表:

create table part_t
(id integer) partition by hash (id);
create table part_t_p1
partition of part_t for values with (modulus 4, remainder 0);
create table part_t_p2
partition of part_t for values with (modulus 4, remainder 1);
create table part_t_p3
partition of part_t for values with (modulus 4, remainder 2);
create table part_t_p4
partition of part_t for values with (modulus 4, remainder 3);insert into part_t select generate_series(1,100);

我们可以通过以下查询返回每行数据所在的分区:

hrdb=> select tableoid::regclass, id
hrdb-> from part_t
hrdb-> order by id
hrdb-> limit 10;tableoid  | id
-----------+----part_t_p1 |  1part_t_p3 |  2part_t_p2 |  3part_t_p4 |  4part_t_p2 |  5part_t_p4 |  6part_t_p4 |  7part_t_p2 |  8part_t_p2 |  9part_t_p4 | 10
(10 rows)

对于集合操作 UNION、INTERSECT、EXCEPT 也是如此:

hrdb=> select tableoid::regclass, col from test
hrdb-> union all
hrdb-> select tableoid::regclass, id from part_t where id < 4
hrdb-> order by 2;tableoid  | col
-----------+-----test      |   1part_t_p1 |   1test      |   2part_t_p3 |   2test      |   3part_t_p2 |   3
(6 rows)

ctid

ctid 字段代表了数据行在表中的物理位置,也就是行标识(tuple identifier),由一对数值组成(块编号和行索引)。ctid 类似于 Oracle 中的伪列 ROWID。

ctid 可以用于快速查找表中的数据行,也可以用于修复数据损坏。另外,它也可以用于查找并删除表中的重复数据。例如:

insert into test(col)
values (1),(2),(3);hrdb=> select ctid, * from test;ctid  | col
-------+-----(0,1) |   1(0,2) |   2(0,3) |   3(0,4) |   1(0,5) |   2(0,6) |   3
(6 rows)

我们为 test 表插入了 3 条重复的数据。接下来利用 ctid 删除重复的数据:

hrdb=> delete from test
hrdb-> where ctid not in
hrdb-> (
hrdb(>   select max(ctid)
hrdb(>   from test
hrdb(>   group by col
hrdb(> );
DELETE 3

需要注意的是,ctid 的值有可能会改变(例如 VACUUM FULL);因此,ctid 不适合作为一个长期的行标识,应该使用主键作为行的逻辑标识。

xmin

xmin 代表了该行版本(row version )的插入事务 ID(XID)。行版本是数据行的具体状态,每次更新操作都会为相同的逻辑行创建一个新的行版本(多版本并发控制,MVCC)。事务 ID 是一个 32 bit 数字。

我们继续为 test 表插入几条数据,并查看它们的 xmin:

hrdb=> insert into test(col) values(4);
INSERT 0 1
hrdb=> insert into test(col) values(5);
INSERT 0 1hrdb=> select xmin,col from test;xmin | col
------+-----2852 |   12852 |   22852 |   32854 |   42855 |   5
(5 rows)

xmin 字段可以用于查看数据行的插入时间:

hrdb=> select col,
hrdb->        to_char(pg_xact_commit_timestamp(xmin) ,'YYYY-MM-DD HH24:MI:SS') AS insert_time
hrdb-> from test;col |     insert_time
-----+---------------------1 | 2020-05-28 16:52:082 | 2020-05-28 16:52:083 | 2020-05-28 16:52:084 | 2020-05-28 17:03:335 | 2020-05-28 17:03:35
(5 rows)

注意,系统函数 pg_xact_commit_timestamp 需要将配置参数 track_commit_timestamp 设置为 on 才能使用。

xmax

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

我们查看一下 test 表中的 xmax:

hrdb=> select txid_current();txid_current
--------------2858
(1 row)hrdb=> select xmax, col from test;xmax | col
------+-----0 |   10 |   20 |   30 |   40 |   5
(5 rows)

然后打开另一个会话,在事务中修改 test 表中的数据:

-- 会话 2
hrdb=> update test
hrdb-> set col= col*2;
UPDATE 5

回到第一个会话,再次查看 xmax:

hrdb=> select xmax, col from test;xmax | col
------+-----2858 |   12858 |   22858 |   32858 |   42858 |   5
(5 rows)

2858 是第二个会话的事务 ID,它是删除这些行版本的事务。PostgreSQL 中的 UPDATE 相当于 DELETE 加 INSERT。

将第二个事务回滚:

-- 会话 2
hrdb=> rollback;
ROLLBACK

如果再次查询 test 表中的 xmax,仍然返回 2858。

xmax 还有可能表示当前正在占用行锁的事务 ID,利用 PostgreSQL 扩展插件 pageinspect 可以获取详细信息:

create extension pageinspect;select t.col,t.xmaxcasewhen (t_infomask & 128)::boolean then 'LOCK'when (t_infomask & 1024)::boolean then 'COMMITTED'when (t_infomask & 2048)::boolean then 'ROLLBACKED'when (t_infomask & 4096)::boolean then 'MULTI XACT'end as xmax_info
from test t
left outer join heap_page_items(get_raw_page('test', 0)) hp on (t.ctid = hp.t_ctid)
where hp.t_xmax = t.xmax;

cmin

cmin 代表了插入事务中的命令标识符(从 0 开始)。命令标识符是一个 32 bit 数字。

cmax

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

我们先查看一下 test 表中的

hrdb=> select cmin, cmax, col from test;cmin | cmax | col
------+------+-----0 |    0 |   10 |    0 |   20 |    0 |   30 |    0 |   40 |    0 |   5
(5 rows)

然后在事务中修改数据:

hrdb=> begin;
BEGIN
hrdb=> select txid_current();txid_current
--------------2859
(1 row)hrdb=> insert into test(col) values(6);
INSERT 0 1
hrdb=> insert into test(col) values(7);
INSERT 0 1
hrdb=> insert into test(col) values(8);
INSERT 0 1hrdb=> select cmin, cmax, col from test;cmin | cmax | col
------+------+-----0 |    0 |   10 |    0 |   20 |    0 |   30 |    0 |   40 |    0 |   50 |    0 |   61 |    1 |   72 |    2 |   8
(8 rows)

然后删除一条记录:

hrdb=> delete from test where col=1;
DELETE 1

此时,从另一个会话中查看:

-- 会话 2
hrdb=> select cmin, cmax, col from test;cmin | cmax | col
------+------+-----3 |    3 |   10 |    0 |   20 |    0 |   30 |    0 |   40 |    0 |   5
(5 rows)

oid

如果使用 PostgreSQL 11 或者更早版本,还有一个隐藏的系统字段:oid。它代表了数据行的对象 ID,只有当创建表时使用了 WITH OIDS 选项或者配置参数 default_with_oids 设置为 true 时才会创建这个字段。

从 PostgreSQL 12 开始,不再支持 WITH OIDS 选项,oid 只用于系统内部。

总结

PostgreSQL 中的每个表都包含了 6 个隐藏的系统字段,可以用于获取关于数据行的一些内部信息。这些字段名称不能用于创建普通的字段,即使使用双引号包含也不可以。

如果你点击了收藏⭐,请不要忘了关注❤️、评论

PostgreSQL 中的系统字段:tableoid、xmin、xmax、cmin、cmax、ctid相关推荐

  1. ABAP 编程语言中的系统字段(System Fields)

    ABAP 系统字段,给应用开发人员提供了当前系统相关信息. BC400 教材上给出了部分例子: 下面我们写一些简单的 ABAP 代码,来熟悉系统字段的用法. 就一行语句:WRITE:/ sy-unam ...

  2. mysql text 独立表,当您在MySQL或PostgreSQL中拥有TEXT字段时,是否应该将其放在单独的表中?...

    I've heard that if you have a table with a TEXT column that will hold a large chunk of text data, it ...

  3. PostgreSQL中的MVCC机制

    MVCC,Multi-Version Concurrency Control,多版本并发控制. 一句话讲,MVCC就是用同一份数据临时保留多版本的方式,实现并发控制.它可以避免读写事务之间的互相阻塞, ...

  4. postgresql源码学习(49)—— MVCC⑤-cmin与cmax 同事务内的可见性判断

    一. 难以理解的场景 postgresql源码学习(十九)-- MVCC④-可见性判断 HeapTupleSatisfiesMVCC函数_Hehuyi_In的博客-CSDN博客 在前篇的可见性判断中有 ...

  5. PostgreSQL 从cmin/cmax到combo cid

    cmin和cmax介绍 cmin和cmax是PostgreSQL中表的系统字段之一,用来判断同一个事务内的其他命令导致的行版本变更是否可见.即在事务中每个命令都应该能看到其之前执行的命令的变更. 很多 ...

  6. PostgreSQL从cmin/cmax到combo cid

    作者:吴聪 cmin和cmax介绍 cmin和cmax是PostgreSQL中表的系统字段之一,用来判断同一个事务内的其他命令导致的行版本变更是否可见.即在事务中每个命令都应该能看到其之前执行的命令的 ...

  7. KingbaseES 中的xmin,xmax等系统字段说明

    在KingbaseES中,当我们创建一个数据表时,数据库会隐式增加几个系统字段.这些字段由系统进行维护,用户一般不会感知它们的存在. 例如,以下语句创建了一个简单的表: create table te ...

  8. Yigo平台中系统自带的五个系统字段值

    如图: 系统字段不允许编辑,不允许删除 一·OID是主表的对象标识,SOID用于定义其他表与主表之间的关系.如图所示: OID:对象标识,是一条数据的唯一标识 SOID:主对象标识,用来主表跟其他表进 ...

  9. PostgreSQL学习手册(系统表)

    一.pg_class: 该系统表记录了数据表.索引(仍然需要参阅pg_index).序列.视图.复合类型和一些特殊关系类型的元数据.注意:不是所有字段对所有对象类型都有意义. 名字 类型 引用 描述 ...

最新文章

  1. Linux查看文件编码格式及文件编码转换
  2. 为维护视图创建事物码
  3. Dreamweaver Flash Photoshop网页设计综合应用 (智云科技) [iso] 1.86G​
  4. C++笔记-Qt中使用Lambda时[]中的形式
  5. python3用什么软件_apt-get 如何给python3装软件?
  6. 算法 Tricks(二) —— 大数的处理
  7. 代码修改及模型复查 12-6
  8. 《思考,快与慢》读书笔记
  9. 【已解决】平板远程控制WIN10电脑
  10. 【微波技术与电路】02 有界空间的微波
  11. 无人驾驶车辆控制(三):纯跟踪算法(Pure Pursuit)
  12. 域名dns被劫持怎么办、dns被劫持怎么办、dns被劫持的解决方法
  13. c语言编写坦克大战设计报告,c语言编写坦克大战源代码
  14. 手把手带你领略graphql的魅力
  15. 连接HC-05与HC-06
  16. 安卓7.0及以上用户证书导入的问题
  17. translation的使用
  18. 2018山东计算机录取分数,【分数线】2018山东省公费师范生分数线汇总
  19. android 百度地图距离计算器,Stata:我和她离多远?基于百度地图API的地理距离计算...
  20. 《天龙八部》通关攻略 二

热门文章

  1. MVC中集成Hangfire定时任务
  2. Java多线程复习整理(二)
  3. 查看知乎404问题解决办法
  4. 【每日一GO】加密解密库—dongle
  5. 计算机无法读取配置文件,由于权限不足,无法读取配置文件
  6. 存储空间不足,无法完成此操作
  7. 毕业设计 python的微信公众平台机器人
  8. 请简述SSM框架整合思路。
  9. 网页JS自动化脚本(一)安装油猴或暴力猴等脚本管理器并新建脚本
  10. MCU芯片设计和软件开发