WEBKT

PostgreSQL VACUUM 监控实战:pg_stat_all_tables 与 pg_stat_progress_vacuum 详解

125 0 0 0

为什么需要监控 VACUUM?

pg_stat_all_tables:表级别的统计信息

常用字段

示例查询

解读关键指标

案例分析

pg_stat_progress_vacuum:VACUUM 进度监控

常用字段

示例查询

解读关键指标

案例分析

结合使用两个视图

常见问题及排查

总结

大家好,我是你们的 PostgreSQL 好伙伴“老司机”。今天咱们来聊聊 PostgreSQL 中一个非常重要,但又经常被忽视的维护操作——VACUUMVACUUM 就像数据库的“清洁工”,负责清理那些“死元组”(dead tuples,也就是被删除或更新的旧数据行),回收空间,防止数据库膨胀。更重要的是,它还能防止事务 ID 回卷(transaction ID wraparound)带来的灾难性后果。

但是,VACUUM 运行起来可不是“静悄悄”的,它需要消耗资源,有时候甚至会影响数据库的性能。所以,我们需要密切监控 VACUUM 的运行状态,确保它在“默默奉献”的同时,不会给我们的业务带来负面影响。今天,我就来给大家介绍两个监控 VACUUM 的利器:pg_stat_all_tablespg_stat_progress_vacuum,并通过实际案例,教你如何解读这些视图中的关键指标,判断 VACUUM 是否正常工作,以及如何发现潜在问题。

为什么需要监控 VACUUM?

在深入了解这两个视图之前,我们先来搞清楚,为什么我们需要监控 VACUUM

  • 防止数据库膨胀: VACUUM 最主要的作用就是回收“死元组”占用的空间。如果不及时清理,数据库文件会越来越大,占用磁盘空间,影响性能。
  • 防止事务 ID 回卷: PostgreSQL 使用事务 ID(XID)来标识每个事务。XID 是一个 32 位整数,用完之后会“回卷”到起始值。如果数据库长时间不进行 VACUUM,旧的 XID 可能无法及时回收,导致 XID 耗尽,数据库将停止写入,后果非常严重。
  • 优化查询性能: “死元组”过多会降低查询性能,因为数据库在扫描数据时需要跳过这些“死元组”。VACUUM 可以减少“死元组”数量,提高查询效率。
  • 避免 VACUUM 运行时间过长: VACUUM 操作可能会阻塞其他数据库操作,特别是 VACUUM FULL。我们需要监控 VACUUM 的运行时间,避免它长时间占用资源,影响业务。
  • 发现潜在问题: VACUUM 运行异常可能预示着某些潜在问题, 例如长时间运行的事务, 导致无法回收死元组.

pg_stat_all_tables:表级别的统计信息

pg_stat_all_tables 视图提供了表级别的统计信息,包括 VACUUMANALYZE 的相关信息。我们可以通过这个视图了解每个表上次 VACUUMANALYZE 的时间、执行次数、“死元组”数量等信息。

常用字段

  • relname: 表名。
  • last_vacuum: 上次手动 VACUUM 的时间(不包括 autovacuum)。
  • last_autovacuum: 上次自动 VACUUM (autovacuum) 的时间。
  • vacuum_count: 手动 VACUUM 的次数。
  • autovacuum_count: 自动 VACUUM 的次数。
  • last_analyze: 上次手动 ANALYZE 的时间。
  • last_autoanalyze: 上次自动 ANALYZE 的时间。
  • analyze_count: 手动 ANALYZE 的次数。
  • autoanalyze_count: 自动 ANALYZE 的次数。
  • n_live_tup: 表中“活元组”(live tuples)的数量,也就是当前有效的数据行数。
  • n_dead_tup: 表中“死元组”的数量。
  • n_mod_since_analyze: 自上次 ANALYZE 以来,表中被修改的元组数量。

示例查询

我们可以通过以下 SQL 查询来查看 pg_stat_all_tables 中的信息:

SELECT
relname,
last_vacuum,
last_autovacuum,
vacuum_count,
autovacuum_count,
last_analyze,
last_autoanalyze,
analyze_count,
autoanalyze_count,
n_live_tup,
n_dead_tup,
n_mod_since_analyze
FROM
pg_stat_all_tables
ORDER BY
n_dead_tup DESC;

这个查询会按照“死元组”数量降序排列,方便我们找出“死元组”最多的表。

解读关键指标

  • last_vacuumlast_autovacuum: 这两个字段可以帮助我们了解表上次 VACUUM 的时间。如果这两个时间都比较久远,说明这个表可能长时间没有进行 VACUUM 了,需要关注。
  • n_dead_tup: 这个字段表示表中“死元组”的数量。如果这个值很大,说明这个表需要进行 VACUUM 了。一般来说,如果 n_dead_tup 超过 n_live_tup 的一定比例(例如 10% 或 20%),就需要考虑进行 VACUUM
  • vacuum_countautovacuum_count: 查看vacuum执行的次数, 了解vacuum的频率.
  • 注意: n_dead_tup 只是一个估算值, 并不完全精确. 并且, n_dead_tup 的数量并不能完全决定是否需要执行 VACUUM.

案例分析

假设我们通过上面的查询发现,表 my_tablelast_autovacuum 时间是 3 天前,n_dead_tup 是 10000,n_live_tup 是 50000。这说明 my_table 已经 3 天没有进行自动 VACUUM 了,而且“死元组”数量占到了“活元组”数量的 20%。这可能意味着 autovacuum 的配置不合理,或者 autovacuum 进程遇到了问题。我们需要进一步调查,看看是什么原因导致 autovacuum 没有及时运行。

pg_stat_progress_vacuumVACUUM 进度监控

pg_stat_progress_vacuum 视图提供了正在运行的 VACUUM 操作的进度信息。我们可以通过这个视图了解 VACUUM 正在处理哪个表、已经处理了多少数据、还剩多少数据等信息。

常用字段

  • pid: VACUUM 进程的 PID。
  • datid: 数据库 OID。
  • datname: 数据库名称。
  • relid: 正在进行 VACUUM 的表的 OID。
  • phase: VACUUM 当前所处的阶段。PostgreSQL 12 以及之前的版本, 包含如下阶段:
    • initializing: 初始化阶段。
    • scanning heap: 扫描堆(heap)阶段,查找“死元组”。
    • vacuuming indexes: 清理索引阶段。
    • vacuuming heap: 清理堆阶段。
    • cleaning up indexes: 再次清理索引阶段。
    • truncating heap: 截断堆阶段。
    • performing final cleanup: 执行最终清理阶段。
      PostgreSQL 13 及之后的版本新增了 scanning index 阶段.
  • heap_blks_total: 表的总块数。
  • heap_blks_scanned: 已扫描的块数。
  • heap_blks_vacuumed: 已清理的块数。
  • index_vacuum_count: 已清理的索引数量。
  • max_dead_tuples: 允许的最大“死元组”数量。
  • num_dead_tuples: 当前已发现的“死元组”数量。

示例查询

我们可以通过以下 SQL 查询来查看 pg_stat_progress_vacuum 中的信息:

SELECT
pid,
datname,
relid,
phase,
heap_blks_total,
heap_blks_scanned,
heap_blks_vacuumed,
index_vacuum_count,
max_dead_tuples,
num_dead_tuples
FROM
pg_stat_progress_vacuum;

解读关键指标

  • phase: 这个字段表示 VACUUM 当前所处的阶段。我们可以通过这个字段了解 VACUUM 的进度。例如,如果 phasescanning heap,说明 VACUUM 正在扫描堆,查找“死元组”。
  • heap_blks_totalheap_blks_scannedheap_blks_vacuumed: 这三个字段可以帮助我们了解 VACUUM 已经处理了多少数据,还剩多少数据。我们可以通过计算 heap_blks_scanned / heap_blks_total 来估算 VACUUM 的进度。
  • index_vacuum_count: 已清理的索引数量.
  • 如果查询结果为空, 则表示当前没有正在运行的 VACUUM 进程.

案例分析

假设我们通过上面的查询发现,有一个 VACUUM 进程正在处理表 my_tablephasevacuuming heapheap_blks_total 是 1000,heap_blks_scanned 是 800,heap_blks_vacuumed 是 600。这说明 VACUUM 已经扫描了 80% 的数据块,清理了 60% 的数据块,进度已经过半。我们可以继续观察这个进程,直到它完成。

结合使用两个视图

pg_stat_all_tablespg_stat_progress_vacuum 这两个视图通常需要结合使用,才能更全面地了解 VACUUM 的运行状态。

  1. 首先,通过 pg_stat_all_tables 找出需要关注的表。 我们可以根据 last_vacuumlast_autovacuumn_dead_tup 等字段,找出长时间没有进行 VACUUM 或者“死元组”数量较多的表。
  2. 然后,通过 pg_stat_progress_vacuum 监控正在运行的 VACUUM 进程。 我们可以了解 VACUUM 的进度、所处的阶段等信息。
  3. 如果发现 VACUUM 运行时间过长或者卡住,需要进一步调查原因。 可能是因为有长时间运行的事务阻塞了 VACUUM,或者是因为 VACUUM 的配置不合理。

常见问题及排查

  • VACUUM 运行时间过长: 可能是因为有长时间运行的事务阻塞了 VACUUM。可以通过 pg_stat_activity 视图查看当前正在运行的事务,找出长时间运行的事务并进行处理。也有可能是表非常大,导致 VACUUM 需要很长时间才能完成。可以考虑使用 VACUUM FULL(会锁定表,谨慎使用)或者调整 autovacuum 的参数,加快 VACUUM 的速度。
  • VACUUM 卡住: 可能是因为遇到了锁冲突。可以通过 pg_locks 视图查看当前的锁信息,找出导致锁冲突的进程并进行处理。
  • autovacuum 没有及时运行: 可能是因为 autovacuum 的配置不合理。可以检查 autovacuum_vacuum_thresholdautovacuum_vacuum_scale_factorautovacuum_naptime 等参数,根据实际情况进行调整。也可以检查 autovacuum 进程是否正常运行。
  • n_dead_tup 持续增长: 可能是因为有大量的删除或更新操作,导致产生了大量的“死元组”。可以考虑优化应用程序,减少不必要的删除或更新操作。也可以调整 autovacuum 的参数,让 autovacuum 更频繁地运行。
  • VACUUM 后性能没有明显提升: 可能是因为 VACUUM 并没有清理多少“死元组”。可以检查 VACUUM 的日志,看看是否有错误信息。也有可能是因为其他原因导致性能问题,例如索引缺失、查询语句不优化等。

总结

VACUUM 是 PostgreSQL 中非常重要的维护操作,我们需要密切监控它的运行状态,确保它正常工作。pg_stat_all_tablespg_stat_progress_vacuum 是两个非常有用的视图,可以帮助我们了解 VACUUM 的相关信息。通过结合使用这两个视图,并结合实际案例进行分析,我们可以及时发现并解决 VACUUM 相关的问题,保证数据库的健康运行。

希望今天的分享对大家有所帮助。如果你还有其他关于 PostgreSQL 的问题,欢迎在评论区留言,我会尽力解答。记住,数据库的健康,需要我们每个“老司机”的细心呵护!

PostgreSQL老司机 PostgreSQLVACUUM数据库维护

评论点评

打赏赞助
sponsor

感谢您的支持让我们更好的前行

分享

QRcode

https://www.webkt.com/article/7776