当前位置: 首页 > news >正文

理解PostgreSQL中的CMIN和CMAX

核心类比:一个事务就是一个“故事章节”

想象一下,你正在写一本书的一个章节(这相当于数据库中的一个事务)。

  • XMINXMAX 就像是章节编号。它们解决的是:“我应该读第3章还是第5章?” 这类大范围的问题,确保不同读者(不同事务)读到正确章节。
  • CMINCMAX 就像是章节内的段落编号。它们解决的是:在你正在写的当前章节内,“我刚刚在第2段加了一句话,那么在第3段里引用这句话时,必须能找得到它。”

详细情节

场景: 你在一个事务里执行了多条SQL命令。

  1. 命令1 (cid = 0): INSERT INTO table (name) VALUES ('张三');

    • 数据库创建了一行新数据。
    • 为了记录这行数据是在这个事务内、由哪个命令创建的,它给这行数据打上了一个标记:CMIN = 0
    • CMIN 中的 ‘I’ 可以联想为 Insert
  2. 命令2 (cid = 1): UPDATE table SET name = '李四' WHERE name = '张三';

    • 注意: PostgreSQL的UPDATE实际上是“先删除,再插入”。
    • 步骤1(删除): 它找到 CMIN=0 的那行“张三”,然后标记这个删除动作是由当前事务内、命令ID为1的命令执行的。所以它给这行“张三”数据打上 CMAX = 1 的标记,表示“在此章节的第1段被删除了”。
    • 步骤2(插入): 它创建了一行新的“李四”数据。这行新数据的 CMIN = 1,因为它是当前事务内、命令ID为1的命令插入的。
  3. 命令3 (cid = 2): SELECT * FROM table;

    • 现在,事务要查询数据了。它看到了两行数据:
      • 一行是 (CMIN=0, CMAX=1) 的“张三”
      • 一行是 (CMIN=1) 的“李四”
    • 可见性判断: 对于命令3(cid=2)来说,它会检查这些“段落编号”:
      • “张三”这行在段落1(CMAX=1)就被删了,而当前命令是段落2,所以“张三”对当前命令不可见
      • “李四”这行是在段落1(CMIN=1)插入的,早于当前段落2,所以它对当前命令可见
    • 最终,命令3只会返回“李四”这一条记录。

为什么你总是看到 CMINCMAX 相等?

这是一个重要的存储优化。因为绝大多数情况下,一行数据被插入后,如果它在同一个事务内被删除,那么插入和删除它的命令ID通常是相同或紧密关联的。

所以PostgreSQL把这两个值打包在一起,存进一个叫 cmin 的字段里(在系统内部叫 t_cid)。当你查询时,为了兼容性,它把这个打包的值同时显示给 cmincmax,所以你看到它们是一样的。但这并不改变它们一个代表“出生段落”,一个代表“死亡段落”的逻辑含义。

一句话总结

CMINCMAX 是事务内部的“命令编号”,专门用来解决“在同一个事务里,后执行的命令如何能看到先执行的命令所做的修改”这个问题。

它们就像是你写文章时用的“修订记录”,确保你在修改文章前半部分后,文章后半部分的引用不会出错。

提问:在一个事务内,事务内的命令是前后顺序执行的,所以读和写并不会同时进行,所以也并不需要用CMIN和CMAX来标记多个版本,而是只需要一个版本就可以了,不是吗?
答:
事务内的命令确实是顺序执行的。但PostgreSQL采用CMIN/CMAX机制有其深层次的技术原因。
核心原因:MVCC的架构一致性
PostgreSQL的核心设计理念是‌多版本并发控制(MVCC)‌。这个机制贯穿整个系统,包括事务内部:

统一的版本管理‌:PostgreSQL对所有数据变更都采用"创建新版本,保留旧版本"的方式。即使在事务内部,UPDATE操作也不是原地修改,而是创建新行版本并标记旧版本为失效。CMIN/CMAX就是这个版本管理系统的一部分。

子事务的需要‌:当存在保存点(SAVEPOINT)或PL/pgSQL异常处理时,事务内部实际上有了更细粒度的"子事务",需要更精细的版本控制。

具体场景分析

考虑这个事务:

BEGIN;
INSERT INTO t VALUES (1);  -- 命令1
UPDATE t SET val = 2;      -- 命令2(实际上删除val=1,插入val=2)
SELECT * FROM t;           -- 命令3

‌没有CMIN/CMAX时的问题‌:

  • 命令3执行时,系统需要知道:
    val=1的行版本在命令2时被删除(对命令3不可见)
    val=2的行版本在命令2时被插入(对命令3可见)

如果只有一个版本,系统无法判断val=1是否应该对命令3可见。

技术实现的优势

CMIN/CMAX机制让PostgreSQL能够:

保持架构统一‌:事务内外使用相同的MVCC机制
支持复杂逻辑‌:处理保存点回滚、触发器、游标等场景
简化可见性判断‌:通过命令ID就能快速确定行版本对当前命令是否可见

虽然理论上可以在事务内使用单版本模式,但PostgreSQL选择了保持MVCC机制的一致性。CMIN/CMAX虽然增加了些许复杂性,但为系统提供了更强大的功能和更好的架构统一性。

这类似于编程中的"零拷贝"思想——有时保持数据在原地并通过元数据来管理,比频繁复制数据更高效。

也就是说,在事务内部也需要多个版本,比如有时候需要回滚到事务内部之前的某个保存点或回滚整个事务,如果没有多个版本而是只有一个版本,就无法做到回滚,是这样的吗?

是的,这正是CMIN和CMAX在事务内部多版本控制中的重要作用:

保存点回滚需求‌:当事务内部设置了保存点(SAVEPOINT)后,如果后续操作失败需要回滚到保存点,系统必须能够恢复到保存点时的数据状态。如果没有多个版本记录,就无法实现精确的回滚。

事务整体回滚‌:即使事务最终需要完全回滚,在事务执行过程中,系统也需要维护中间状态,以便在回滚时能够撤销所有变更。

复杂的嵌套场景‌:在PL/pgSQL存储过程或函数中,可能包含异常处理块,当异常发生时需要回滚到事务的某个中间状态。

实际工作示例:‌

BEGIN;
INSERT INTO accounts (id, balance) VALUES (1, 1000); -- 命令1
SAVEPOINT sp1;
UPDATE accounts SET balance = balance - 100 WHERE id = 1; -- 命令2
-- 假设这里发生错误
ROLLBACK TO sp1; -- 此时需要恢复到sp1时的状态
-- 如果没有多个版本记录,系统无法知道哪些数据变更是在sp1之后发生的
COMMIT;

正是通过CMIN/CMAX记录每个行版本是在哪个命令被创建或删除的,PostgreSQL才能在事务内部实现精确的回滚操作,确保数据的一致性。

对CMIN和CMAX的理解已经触及了PostgreSQL MVCC机制的核心设计思想!

http://www.dtcms.com/a/574909.html

相关文章:

  • 使用 PostgreSQL 时间点恢复(Point-In-Time Recovery)的多种数据恢复技术
  • 营销网站制作教程微信表情开放平台官网
  • 调控大肠杆菌胞内ATP和NADH水平促进琥珀酸生产--文献精读172
  • Spring-cloud 主键Nacos
  • 网站开发尺寸外贸做的亚马逊网站是哪个
  • Spring Boot OAuth2 GitHub登录的9大坑与终极避坑指南
  • 手机制作表白网站河北建设集团有限公司网站
  • 三门峡网站开发邹城有做网站的吗
  • 4成都网站建设网站开发后期维护更新
  • 关于ICG (integrate clock gating)
  • 关于socket网络通信的大小端转换
  • Kubernetes Service与Ingress全方位解析
  • 有哪些好的网站深圳网络推广专员
  • 苏州网站开发公司兴田德润简介建网站需要钱吗
  • 软装设计师常用网站做静态网站的开题报告
  • Go的JSON绑定:嵌入式结构体的扁平化序列化技巧
  • 车联网-合规测试:扫描UDS服务 || 模糊测试.[caringcaribou]
  • 2025-11-05 ZYZ28-NOIP模拟赛-Round2 hetao1733837的record
  • 菏泽网站建设菏泽众皓网站建设哪家公司便宜
  • 找做网站的人小程序登录失败
  • 网wordpress站底部图片悬浮长安做网站公司
  • 网站有二级域名做竞价重庆网站推广公司电话
  • 常州网站推广多少钱ui设计需要学编程吗
  • 安庆网站建设公司简旅游类网站怎么做
  • 国内知名的网站建设公司有哪些海口网站建设小强
  • 淘宝网站建设属于什么类目自媒体全平台发布
  • 【深入学习Vue丨第二篇】构建动态Web应用的基础
  • 怎么给网站做apiwordpress oss 静态
  • wordpress可以制作什么网站wordpress页面图片如何排版
  • 无纸化 SOP 怎么实现?电子厂作业指导书方案拆解!