PostgreSQL系统字段cmin和cmax详解

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介: 1.cmin和cmax是什么 PG中每个表都包含了一些系统字段,其中包括cmin和cmax。 cmin:插入该元组的命令在插入事务中的命令标识(从0开始累加) cmax:删除该元组的命令在插入事务中的命令标识(从0开始累加) 可以在Select命令的输出列表中显式地指定系统字段。

1.cmin和cmax是什么

PG中每个表都包含了一些系统字段,其中包括cmin和cmax。
cmin:插入该元组的命令在插入事务中的命令标识(从0开始累加)
cmax:删除该元组的命令在插入事务中的命令标识(从0开始累加)

可以在Select命令的输出列表中显式地指定系统字段。

点击(此处)折叠或打开

  1. postgres=# create table tb1(c1 int);
  2. CREATE TABLE
  3. postgres=# begin;
  4. BEGIN
  5. postgres=# insert into tb1 values(1);
  6. INSERT 0 1
  7. postgres=# insert into tb1 values(2);
  8. INSERT 0 1
  9. postgres=# select xmin,xmax,cmin,cmax,* from tb1;
  10.  xmin | xmax | cmin | cmax | c1
  11. ------+------+------+------+----
  12.  1055 | 0 | 0 | 0 | 1
  13.  1055 | 0 | 1 | 1 | 2
  14. (2 行记录)

  1. postgres=# rollback;
  2. ROLLBACK

2.cmin和cmax的作用

cmin和cmax用于 判断同一个事务内的其他命令导致的行版本变更是否可见。如果一个事务内的所有命令严格顺序执行,那么每个命令总能看到之前该事务内的所有变更,不需要使用命令标识。然而一个事务内存在命令交替执行的情况,比如使用游标进行查询。Fetch游标时看到的是声明游标时的数据快照而不是Fetch执行时,即声明游标后对数据的变更对该游标不可见。

点击(此处)折叠或打开

  1. postgres=# begin;
  2. BEGIN
  3. postgres=# insert into tb1(c1) values(1);
  4. INSERT 0 1
  5. postgres=# declare tb1_v cursor for select xmin,xmax,cmin,cmax,* from tb1;
  6. DECLARE CURSOR
  7. postgres=# update tb1 set c1=2;
  8. UPDATE 1
  9. postgres=# select xmin,xmax,cmin,cmax,* from tb1;
  10.  xmin | xmax | cmin | cmax | c1
  11. ------+------+------+------+----
  12.  1060 | 0 | 1 | 1 | 2
  13. (1 行记录)


  14. postgres=# fetch all from tb1_v;
  15.  xmin | xmax | cmin | cmax | c1
  16. ------+------+------+------+----
  17.  1060 | 1060 | 0 | 0 | 1
  18. (1 行记录)


  19. postgres=# rollback;
  20. ROLLBACK

3.行版本可见性的判断

行版本可见性的完整判断逻辑课参考一下下面的代码注释
Source code comment in src/backend/utils/time/tqual.c:

点击(此处)折叠或打开

  1.  * ((Xmin == my-transaction &&           inserted by the current transaction
  2.  *     Cmin my-command &&              before this command, and
  3.  *     (Xmax is null ||                  the row has not been deleted, or
  4.  *     (Xmax == my-transaction &&        it was deleted by the current transaction
  5.  *     Cmax >= my-command)))             but not before this command,
  6.  * ||                                    or
  7.  *    (Xmin is committed &&              the row was inserted by a committed transaction, and
  8.  *        (Xmax is null ||               the row has not been deleted, or
  9.  *         (Xmax == my-transaction &&    the row is being deleted by this transaction
  10.  *         Cmax >= my-command) ||        but it's not deleted "yet", or
  11.  *         (Xmax != my-transaction &&    the row was deleted by another transaction
  12.  *         Xmax is not committed))))     that has not been committed

4.cmin和cmax的内部存储

出于减少系统字段大小的考虑,cmin和cmax在行版本的头部使用同一个字段t_cid存储,并和t_xvac交叠。所以通过系统字段看到的cmin和cmax的值总是相同的。

src/include/access/htup.h:
点击( 此处)折叠或打开
  1. typedef struct HeapTupleFields
  2. {
  3.     TransactionId t_xmin;     /* inserting xact ID */
  4.     TransactionId t_xmax;     /* deleting or locking xact ID */

  5.     union
  6.     {
  7.         CommandId t_cid;      /* inserting or deleting command ID, or both */
  8.         TransactionId t_xvac; /* old-style VACUUM FULL xact ID */
  9.     } t_field3;
  10. } HeapTupleFields;

当xmax为0,即行版本还没有被删除时,t_cid代表插入命令的命令标识。
当xmax不为0,且插入事务标识xmin和删除事务标识xmax不同时,t_cid代表删除命令的命令标识。
当xmax不为0,且插入事务标识xmin和删除事务标识xmax相同时,t_cid代表组合命令标识。在backend的私有空间存储了组合命令标识到实际的{cmin,cmax}组合的映射。
执行VACUUM FULL时不需要cmin和cmax,所以t_xvac可以和t_cid共用一个存储空间。

5.命令标识的分配

我们注意到不是每次执行 命令,都会导致命令标识增加。 命令标识的分配规则如下:
1)每个命令使用事务内全局的命令标识计数器的当前值作为命令标识。
2)事务开始时,命令标识计数器被置为初值0
3)执行更新性的SQL(包括insert,update,delete,select ... for update等)时,在SQL执行后命令标识计数器增1
4)当命令标识计数器经过不断累加又回到初值0时,报错"cannot have more than 2^32-1 commands in a transaction"

由此可得出如下结论
1)非更新性的SQL和其后的第一个更新性SQL的 命令标识相同
2)同一个事务内的插入或删除行为对当前命令有效的条件是 cmin(或cmax) 命令标识。
这就可以解释[3.行版本可见性的判断]中, 命令标识比较时,有时带=,有时不带。






相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
6月前
|
关系型数据库 MySQL 索引
MySQL数据表添加字段的三种方式
MySQL数据表添加字段的三种方式
5795 0
|
1月前
|
分布式计算 关系型数据库 MySQL
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
57 8
|
1月前
|
关系型数据库 MySQL 索引
MySQL的group by与count(), *字段使用问题
正确使用 `GROUP BY`和 `COUNT()`函数是进行数据聚合查询的基础。通过理解它们的用法和常见问题,可以有效避免查询错误和性能问题。无论是在单列分组、多列分组还是结合其他聚合函数的场景中,掌握这些技巧和注意事项都能大大提升数据查询和分析的效率。
145 0
|
1月前
|
关系型数据库 MySQL Java
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
34 0
|
6月前
|
分布式计算 DataWorks MaxCompute
DataWorks产品使用合集之需要将mysql 表(有longtext类型字段) 迁移到odps,但odps好像没有对应的类型支持,该怎么办
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
3月前
|
SQL 关系型数据库 MySQL
MySQL数据库中给表添加字段并设置备注的脚本编写
通过上述步骤,你可以在MySQL数据库中给表成功添加新字段并为其设置备注。这样的操作对于保持数据库结构的清晰和最新非常重要,同时也帮助团队成员理解数据模型的变化和字段的具体含义。在实际操作中,记得调整脚本以适应具体的数据库和表名称,以及字段的详细规范。
89 8
|
2月前
|
SQL 存储 关系型数据库
MySQL新增字段/索引会不会锁表?
MySQL新增字段/索引会不会锁表?
240 0
|
2月前
|
SQL 关系型数据库 MySQL
MySQL 查询某个字段含有字母数字的值
MySQL 查询某个字段含有字母数字的值
90 0
|
2月前
|
存储 关系型数据库 MySQL
MySQL 字符字段长度设置详解:语法、注意事项和示例
MySQL 字符字段长度设置详解:语法、注意事项和示例
281 0
|
2月前
|
关系型数据库 MySQL 数据库管理
MySQL技术指南:如何更改数据字段的前几位数字
MySQL技术指南:如何更改数据字段的前几位数字
67 0