Postgres 中的"删除"比你想象得贵:大规模删除性能优化实践
DBOS 团队在做基于 Postgres 的持久化执行库时发现:大规模批量删除旧 workflow 居然比执行它们还慢。根本原因是 MVCC:Postgres 的 DELETE 只是给行打戳标记为“死元组”,不会真正释放磁盘空间,旧版本要靠 VACUUM 清理。 加上外键 ON DELETE CASCADE 让删除散落在不同磁盘页上的子表数据,缓存局部性差,性能进一步恶化。解决办法包括:放弃外键、按表物理创建顺序分批删除,并在每轮清理前后手动 VACUUM。 文中还详细复盘了一个“索引查找耗时 20 分钟”的诡异 bug——由于死元组堆积在 created_at 索引最前端,查询必须逐个回表验证元组是否真的存活,导致最坏情况下的性能崩溃。 最后解释了为什么没有采用按时间分区再 DROP PARTITION 的方案:那种方式对短期数据很高效,但对长运行 workflow 和复杂保留策略不友好。 整体是面向 Postgres 用户的实用性工程优化文章,对理解 MVCC 删除行为、索引扫描、VACUUM 时机、缓存局部性、外键取舍有较高参考价值。