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

PostgreSQL中MVCC实现机制

MVCC原理

多版本并发控制(Multi-Version Concurrency Control, MVCC) , 是数据库中并发访问数据时保证数据一致性的一种方法。

在并发操作中, 当正在写时, 如果有用户在读, 这时写可能只写了一半, 如一行的前半部分刚写入, 后半部分还没有写入, 这时可能读的用户读取到的数据行的前半部分数据是新的, 后半部分数据是原来的, 这就导致了数据一致性问题。

解决这个问题的最简单的方法是使用读写锁, 写的时候不允许读, 正在读的时候也不允许写, 但这种方法会导致读和写的操作不能并发执行。
于是, 有人想到了一种能够让读写并发执行的方法, 这种方法就是MVCC。
MVCC方法是写数据时, 原数据并不删除, 并发的读还能读到原数据, 这样就不会有数据一致性问题了。

实现MVCC的方法有以下两种:

  • 第一种: 写新数据时, 把原数据移到一个单独的位置, 如回滚段中, 其他用户读数据时, 从回滚段中把原数据读出来。
  • 第二种: 写新数据时, 原数据不删除, 而是把新数据插入进来。

PostgreSQL数据库使用的是第二种方法, 而Oracle数据库和MySQL数据库中的InnoDB引擎使用的是第一种方法。

PostgreSQL中的多版本并发控制

PostgreSQL中的多版本实现是通过把原数据留在数据文件中, 新插入一条数据来实现多版本的功能的。
每张表上都有4个系统字段“xmin”“xmax”“cmin”“cmax”, 这4个字段就是为多版本的功能而添加的。

字段

类型

含义

xmin

xid

插入该行的事务ID(行的"出生证明")

xmax

xid

删除/更新该行的事务ID(0表示未被删除)

cmin

cid

插入该行的命令序号(同一事务内的第几条语句)

cmax

cid

删除该行的命令序号(同一事务内)

ctid

tid

表示表内的物理位置(第一个数字表示数据行所在的物理块的物理块号, 第二个数字表示数据行在物理块中的行号)

xmin、 xmax、 cmin、 cmax这4个字段在多版本实现中用于控制数据行是否对用户可见。
PostgreSQL将修改前后的数据存储在相同的结构中, 分为以下几种情况:

  • 新插入一行时, 将新插入行的xmin填写为当前的事务ID, xmax填“0”。

  • 修改这一行时, 实际上新插入一行, 原数据行上的xmin不变, xmax改为当前的事务ID, 新数据行上的xmin填为当前的事务ID, xmax填“0”。

如下图所示,lp=2 和 lp=3 的 t_ctid 都是 (0,3)。这说明 UPDATE 操作产生的新旧版本共享同一个 ctid 槽位引用(新版本指向自身,旧版本的 t_ctid 在 UPDATE 时未被修改),但它们是两个独立的物理元组,通过 xmin/xmax 形成版本链。

通过 pageinspect 插件直接读取页面原始内容查看旧行数据

SELECT lp, -- 行指针编号 (Line Pointer) t_ctid, -- 元组的 ctid t_xmin, -- 插入事务ID t_xmax, -- 删除/更新事务ID t_infomask2, -- 属性标志位(含 cmin/cmax) t_hoff, -- 头部长度 t_data -- 原始用户数据(bytea 十六进制) FROM heap_page_items(get_raw_page('t1', 0));

  • 删除一行时, 把被删除行上的xmax填写当前的事务ID,xmax不等于0不一定是死元组

从上面的叙述中就可以知道, xmin就是标记插入数据行的事务ID, 而xmax就是标记删除数据行的事务ID。没有修改数据行的操作, 因为修改数据行, 实际上就是把原数据行上的xmax标记上自己的事务ID(相当于打上删除标记) , 然后再新插入一条记录。所以最新版本的数据即xmax为0的一条。

当两个事务同时访问记录时, 通过参考xmin和xmax的标记判断记录的版本, 根据版本号与自己当前的事务标识进行比较, 确定自己的数据权限。
当删除数据时, 记录并没有从数据块中被删除, 空间也没有立即释放。

PostgreSQL的多版本实现中首先要解决的是原数据的空间释放问题。
PostgreSQL通过运行Vaccum进程来回收之前的存储空间, 默认PostgreSQL数据库中的AutoVacuum是打开
的, 也就是说, 当一个表的更新量达到一定值时(死元组数>50+(0.2×活行数), AutoVacuum自动回收空间。
当然也可以关闭AutoVacuum进程, 然后在业务低峰期手动运行VACUUM命令来回收空间。

在PostgreSQL中, 若一个事务执行失败, 在数据文件中该事务产生的数据并不会在事务回滚时被清理掉。 为什么要这样做呢? 为什么不在事务提交时把这些数据标记成有效,而在事务回滚时把这些数据标记成无效呢?
这是出于效率的考虑。
若事务提交或回滚时再次标记数据, 那这些数据就有可能会被刷新到磁盘中, 再次标记会导致另一次I/O, 从而降低性能。

那么如何知道这些数据是有效还是无效呢?
PostgreSQL通过记录事务的状态来实现。
数据行上记录了xmin和xmax, 只需了解xmin和xmax对应的事务是成功提交还是回滚了, 就可以知道这些数据行是否有效。

PostgreSQL把事务状态记录在pg_xact(旧版本中被称为pg_clog),在数据目录的pg_xact子目录下,

但是pg_xact是一个二进制文件目录不能直接查询,可以通过内置函数 txid_status()确定事务是提交还是回滚

committed: 事务已成功提交 aborted: 事务已回滚(中止) in progress: 事务仍在运行中 null: 事务 ID 太老,状态信息已被清理(见下文“事务 ID 回卷”)

PostgreSQL多版本的优劣分析

Oracle数据库和MySQL数据库的InnoDB引擎也都实现了多版本的功能, 但它们与PostgreSQL的实现方式是不一样的, 在这两个数据库中, 旧版本的数据并不记录在原先的数据块中, 而是被记录在回滚段中, 如果要读取旧版本的数据, 需要根据回滚段的数据重构旧版本数据。

PostgreSQL的多版本机制与Java虚拟机的垃圾回收机制比较相像。
事务提交前, 只需要访问原来的数据即可; 提交后, 系统更新元组的存储标识, 直到Vaccum进程收回为止。

相对于InnoDB和Oracle, PostgreSQL的多版本的优势在于以下几点:

  • 事务回滚可以立即完成, 无论事务进行了多少操作。
  • 数据可以进行很多更新, 不必像Oracle和InnoDB那样需要经常保证回滚段不会被用完, 也不会像Oracle数据库那样, 经常遇到“ORA-1555”错误的困扰。

相对于InnoDB和Oracle, PostgreSQL的多版本的劣势在于以下几点:

  • 旧版本数据需要清理。 PostgreSQL清理旧版本称为VACUUM, 并提供了VACUUM命令进行清理。
  • 旧版本的数据会导致查询更慢一些, 因为旧版本的数据存储于数据文件中, 查询时需要扫描更多的数据块。
http://www.jsqmd.com/news/1152267/

相关文章:

  • STM32 HAL 库 ADC+DMA+FFT 实战:TIM2 触发 1024 点采样,频谱分析 5 步实现
  • 信息安全毕设本科生方向指导
  • 鲁L蒲公英7.8股市日记:忍到底部!
  • Cursor企业级部署必备:.cursorrules安全隔离配置(含敏感代码过滤、跨文件上下文限制、审计日志开关)——仅内部团队流通的合规配置白皮书
  • Linux用户、用户组与文件权限知识点+习题操作讲解
  • STRIDE威胁建模实战:用Microsoft Threat Modeling Tool构建Web应用安全防线
  • Transformer:20 个核心概念全解析
  • Claude Code vs Cursor:谁在真实开发场景中胜出?7大维度压力测试结果首次公开
  • QDD驱动器热管理实战:液冷方案如何将峰值扭矩输出提升30%
  • 再生龙(Clonezilla)磁盘克隆和备份工具详解
  • np的数据处理api
  • 15N120-ASEMI沟槽场截止大功率单管15N120
  • 仅剩72小时可复现的对比实验环境(含完整prompt工程模板+评估脚本):Claude与DeepSeek在医疗问诊场景的F1分数断层真相
  • 工业生产无线专网建设指南:扫码枪不丢包、AGV不中断、MES数据不延时
  • 从127到127.99——ChatGPT浮点型Token计费陷阱:金融级精度控制方案(含OpenAI Billing API实时对账模板)
  • 逸模智造・BIM 效能专栏三:智能开图标注,根除图纸错标漏标
  • 全球首个地层学AI大模型:技术架构、应用场景与开发机遇
  • 无犯罪记录公证在哪里办理?慧办好小程序一键完成公证
  • Claude Commit生成器性能压测报告:单日10万+提交场景下延迟<87ms的底层优化路径(附Benchmark原始数据)
  • Redis与ZooKeeper安全配置:从漏洞修复到纵深防御体系构建
  • 2026国内豆包获客培训机构行业深度调研:选型量化标准、落地痛点与本土GEO趣搜科技实战标杆实证
  • Unity游戏模组加载器MelonLoader:从原理到实战部署与问题解决
  • GBASE技术云享会演讲专辑-AI时代数据库的未来趋势.上
  • ChatGPT 没法订阅Plus 怎么办?2026国内可用 ChatGPT镜像站整理,GPT-5.5免费体验
  • Claude vs DeepSeek:从Token计费陷阱、上下文泄漏风险到审计合规缺口——GDPR/等保2.0双标穿透测试报告
  • DeepSeek与Claude性能对比:72小时压力测试、137项指标分析,这份报告99%的人还没看过
  • 都市领航教育1688阿里巴巴运营培训专业办学能力研究报告
  • 74LS112/74LS74 触发器功能实测:5种类型(RS/JK/D/T/T‘)真值表与波形图对比
  • Z世代一边比价一边为情绪豪掷千金,你的用户画像还准吗?
  • Solidworks 安装步骤,无废话图文详解