PostgreSQL系统字段cmin和cmax详解

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介: 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数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
21天前
|
关系型数据库 MySQL
mysql增加修改删除字段
mysql增加修改删除字段
13 0
|
2月前
|
关系型数据库 MySQL 数据库
MySQL时间字段设置自动更新
MySQL时间字段设置自动更新
26 0
|
2月前
|
SQL 关系型数据库 MySQL
MySQL 用gourp by分组后取某一字段最大值
MySQL 用gourp by分组后取某一字段最大值
|
3月前
|
关系型数据库 PostgreSQL
PostgreSQL排序字段不唯一导致分页查询结果出现重复数据
PostgreSQL排序字段不唯一导致分页查询结果出现重复数据
41 0
|
3月前
|
SQL 关系型数据库 MySQL
学习MySQL中DDL语句的修改字段与删除字段,删除表
学习MySQL中DDL语句的修改字段与删除字段,删除表
|
16天前
|
存储 关系型数据库 MySQL
MySQL数据库性能大揭秘:表设计优化的高效策略(优化数据类型、增加冗余字段、拆分表以及使用非空约束)
MySQL数据库性能大揭秘:表设计优化的高效策略(优化数据类型、增加冗余字段、拆分表以及使用非空约束)
|
5天前
|
关系型数据库 MySQL
MySQL全局库表查询准确定位字段
information_schema.COLUMNS 详细信息查询
184 4
|
12天前
|
SQL 存储 关系型数据库
【mysql】将逗号分割的字段内容转换为多行并group by
【mysql】将逗号分割的字段内容转换为多行并group by
|
23天前
|
SQL 关系型数据库 MySQL
Mysql数据库一个表字段中存了id,并以逗号分隔,id对应的详细信息在另一个表中
Mysql数据库一个表字段中存了id,并以逗号分隔,id对应的详细信息在另一个表中
10 0
|
1月前
|
关系型数据库 MySQL
Mysql基础第十三天,创建计算字段
Mysql基础第十三天,创建计算字段
19 0