You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Postgres如何在堆文件中更新变长记录?

PostgreSQL如何处理变长记录的更新?

嘿,这个问题问到点子上了!PostgreSQL处理变长记录更新的核心逻辑是创建新行并标记旧行已删除,而非直接移动相邻行。具体细节我给你唠清楚:

  • 首先,PostgreSQL的表底层是堆(Heap)存储结构,堆里的行一旦写入就不会在原地修改——不管字段是定长还是变长。当执行UPDATE语句时,数据库会优先在当前数据页的空闲空间里写入一条全新的更新后记录;如果当前页没空间,就会分配新的磁盘块来存储这条新记录。
  • 旧的那条原始记录并不会被直接物理删除,而是被标记为「已删除元组(dead tuple)」。这个标记是通过元组头部的事务ID字段(xmin和xmax)实现的:旧元组的xmax会被设置为执行本次UPDATE的事务ID,以此标记它对当前及后续事务不再可见。
  • 针对变长字段(比如TEXT、BYTEA这类),如果更新后的数据长度超过了数据页的存储阈值(通常是页大小的1/4),PostgreSQL还会把超长的部分存入专门的TOAST表中,新元组里只存指向TOAST数据的指针。旧元组对应的TOAST数据也会被标记为无效,等待后续清理。
  • 为什么不选择移动相邻行?主要是为了性能和MVCC(多版本并发控制)机制:移动相邻行会产生大量磁盘IO操作,严重影响性能;同时,MVCC需要保证不同事务能看到各自对应的行版本,原地修改或移动会破坏这种隔离性,导致读取事务出错。
  • 那些被标记为dead的旧元组,会由VACUUM进程定期清理:回收它们占用的磁盘空间,供后续新行复用。如果是TOAST表中的旧数据,VACUUM也会一并清理掉。

内容的提问来源于stack exchange,提问作者Dmitrey Sysolyatin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:06:47