PostgreSQL 中的死元组(Dead tuple)详解

 更新时间:2026年07月03日 09:10:53   作者:ShiningStar_Li  
PostgreSQL使用MVCC(多版本并发控制)来实现高并发和事务隔离,这与 MySQL (InnoDB) 的机制有很大不同,这篇文章介绍PostgreSQL 中的死元组(Dead tuple)的相关知识,感兴趣的朋友一起看看吧

为什么会有死元组?(MVCC机制)

PostgreSQL 使用 MVCC(多版本并发控制) 来实现高并发和事务隔离。这与 MySQL (InnoDB) 的机制有很大不同。

当你执行 UPDATE 时:

  1. PG 不会直接修改原来的那一行数据。
  2. PG 会将旧行标记为“死亡”(设置 xmax 事务ID)。
  3. PG 会插入一个全新的行,包含更新后的数据。
  4. 结果:表中同时存在“旧版本(死元组)”和“新版本(活元组)”。

当你执行 DELETE 时:

  1. PG 不会直接从磁盘移除该行。
  2. PG 只是将该行标记为“死亡”(设置 xmax 事务ID)。
  3. 结果:该行变成了死元组,依然占据磁盘空间。

为什么要这样做?为了事务隔离。
假设事务 A 正在读取某行数据,此时事务 B 更新了这行数据。

  • 如果 PG 直接覆盖了旧数据,事务 A 就会读到不一致的数据(违反了隔离性)。
  • 通过保留旧版本(死元组),事务 A 可以继续读取它启动时看到的那个版本,而事务 B 读取新版本。互不干扰。

死元组的危害

如果死元组不及时清理,会带来严重后果:

表膨胀(Table Bloat):

  • 表文件越来越大,即使你只存了 1GB 的有效数据,表文件可能高达 10GB(全是死元组)。
  • 导致磁盘空间浪费。

查询性能下降:

  • 扫描表(Seq Scan)或索引时,PG 必须跳过大量的死元组。
  • 索引也会变得庞大且碎片化,降低索引效率。

事务 ID 回卷风险(Transaction ID Wraparound):

  • PG 使用 32 位整数存储事务 ID。如果死元组不被清理(冻结),事务 ID 用完后会发生回卷,导致数据丢失且数据库无法启动。这是 PG 最严重的故障之一。

死元组何时被清理?

死元组不会自动消失,必须由 VACUUM 进程来清理。

清理的条件(Visibility Map)

VACUUM 只能清理那些对所有当前活跃事务都不可见的死元组。

  • 如果有一个长事务(Long-running Transaction)还在运行,并且它可能需要看到某个旧版本的数据,那么 VACUUM 不能删除那个死元组。
  • 这就是你之前遇到 dead row versions cannot be removed yet 的原因。

清理的过程

  • 标记可用:VACUUM 将死元组占用的空间标记为“空闲”,供后续的 INSERTUPDATE 复用。
  • 更新可见性映射(Visibility Map):记录哪些页面完全由活元组组成,加速后续查询。
  • 冻结事务 ID:防止事务 ID 回卷。

注意:普通的 VACUUM 不会缩小表文件的大小(不会归还空间给操作系统),它只是让空间在内部可复用。只有 VACUUM FULL 才会真正缩小文件。

如何监控死元组?

你可以查询系统视图 pg_stat_user_tables 来查看表的死元组情况:

SELECT 
    relname AS table_name, 
    n_live_tup AS live_tuples,   -- 活元组数量
    n_dead_tup AS dead_tuples,   -- 死元组数量
    last_vacuum,                 -- 上次手动 vacuum 时间
    last_autovacuum,             -- 上次自动 vacuum 时间
    last_autoanalyze             -- 上次自动 analyze 时间
FROM pg_stat_user_tables 
ORDER BY n_dead_tup DESC;
  • 健康状态:n_dead_tup 应该接近 0,或者远小于 n_live_tup
  • 危险信号:如果 n_dead_tup 很大(例如几百万),且 last_autovacuum 是很久以前,说明 Autovacuum 失效或被阻塞,表正在严重膨胀。

如何处理过多的死元组?

依赖 Autovacuum(默认推荐)

PostgreSQL 有一个后台进程叫 autovacuum,它会自动检测表的变动并触发 VACUUM。

调优建议:对于高频更新的表,可以单独调整其存储参数:

ALTER TABLE ais41.recentships SET (autovacuum_vacuum_scale_factor = 0.05);

(默认是 0.2,即 20% 的死元组才触发;改为 0.05 表示 5% 就触发,更频繁地清理。)

杀死长事务

如前所述,长事务会阻止 VACUUM 清理死元组。

查找并终止长时间运行的事务:

SELECT pg_terminate_backend(pid) 
FROM pg_stat_activity 
WHERE state != 'idle' 
  AND now() - xact_start > interval '10 minutes';

手动 VACUUM

如果 Autovacuum 跟不上节奏,可以手动执行:

VACUUM VERBOSE ais41.recentships;

重建表(极端情况)

如果表已经极度膨胀(例如 90% 都是死元组),普通 VACUUM 效率太低。

  • 使用 VACUUM FULL(锁表,慎用)。
  • 或使用 pg_repack 插件(在线重组,推荐生产环境使用)。

到此这篇关于PostgreSQL 中的死元组(Dead tuple)详解的文章就介绍到这了,更多相关PostgreSQL 死元组内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • PostgreSQL对数组元素聚合基本方法示例

    PostgreSQL对数组元素聚合基本方法示例

    这篇文章主要为大家介绍了PostgreSQL对数组元素聚合基本方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • postgresql 中的 like 查询优化方案

    postgresql 中的 like 查询优化方案

    这篇文章主要介绍了postgresql 中的 like 查询优化方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 使用PostgreSQL为表或视图创建备注的操作

    使用PostgreSQL为表或视图创建备注的操作

    这篇文章主要介绍了使用PostgreSQL为表或视图创建备注的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 在postgresql中运行sql文件并导出结果的操作

    在postgresql中运行sql文件并导出结果的操作

    这篇文章主要介绍了在postgresql中运行sql文件并导出结果的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • PostgreSQL使用执行计划的入门到实战调优指南

    PostgreSQL使用执行计划的入门到实战调优指南

    在数据库性能优化领域,执行计划(Execution Plan)是开发者与数据库优化器对话的翻译器,PostgreSQL的执行计划不仅揭示了SQL语句的执行路径,更通过成本估算、实际耗时等关键指标,,为性能瓶颈定位提供了科学依据,本文将系统讲解PostgreSQL执行计划的核心机制与调优方法
    2026-01-01
  • Postgresql 数据库转义字符操作

    Postgresql 数据库转义字符操作

    这篇文章主要介绍了Postgresql 数据库转义字符操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • Postgresql 赋予用户权限和撤销权限的实例

    Postgresql 赋予用户权限和撤销权限的实例

    这篇文章主要介绍了Postgresql 赋予用户权限和撤销权限的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 如何在Neo4j与PostgreSQL间实现高效数据同步

    如何在Neo4j与PostgreSQL间实现高效数据同步

    本文详细介绍了如何在Neo4j与PostgreSQL两种数据库之间实现高效数据同步,从基础概念到全量与增量同步的实现策略,结合具体代码与实践案例,为开发者提供了全面的指导,感兴趣的朋友跟随小编一起看看吧
    2024-12-12
  • PostgreSQL 性能优化之服务器参数配置操作

    PostgreSQL 性能优化之服务器参数配置操作

    这篇文章主要介绍了PostgreSQL 性能优化之服务器参数配置操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • postgresql 索引之 hash的使用详解

    postgresql 索引之 hash的使用详解

    这篇文章主要介绍了postgresql 索引之 hash的使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02

最新评论