解析PostgreSQL运行速度下降的原因

发表时间: 2021-01-04 16:58

pg数据库运行一段时间之后,突然变慢了,是时候进行一波vacuum了

死亡数据 Dead tuples

VACUUMPostgreSQL内置的垃圾回收清理工具,用来清理无用的元组数据占用的空间。对于PostgreSQL而言,被删除或者被Update之后过时的数据并不会被物理删除,只有运行了VACUUM命令,这些空间才会被释放。因此,需要周期性地运行VACUUM,尤其是频繁更新的表。

那么问题就来了,如果是DELETE操作,PostgreSQL目前的存储引擎会在原HEAP PAGE中保留老的记录版本,如果是UPDATE操作,则会写入一条新版本。而表上的索引也会产生新版本,索引也会产生新的记录。这些无效的数据被称之为dead tuples,使用VACUUM命令可以清理这些无效数据,显著提升性能。

VACUUM和autovacuum

对于VACUUM,最直接的方式,就是执行手动VACUUM命令,这个命令会清理dead tuples。这个命令会扫描全表,然后清理无效数据。但是要慎用VACUUM FULL,因为加了FULL会锁表,并且会删除所有数据并新建,会导致性能占用比较高。

autovacuum则是一个内置的daemon程序,会在一定情况下自动触发vacuum进程,从而无需手动进行配置

autovacuum 触发参数

两个参数可以配置在启动参数中,也可以通过pg_settings(以下是阿里云RDS默认参数)查到:

  • autovacuum_vacuum_threshold = 50
  • autovacuum_vacuum_scale_factor = 0.02

pg_stat_all_tables.n_dead_tup超过了

threshold + pg_class.reltuples * scale_factor

那么VACUUM就会被触发了。

实战总结

  1. 大部分情况下默认参数是足够的
  2. 默认参数不够用的情况下,可以调整autovacuum_vacuum_scale_factor,但是需要重启
  3. 可以通过查询计划判断是否有查询过多的记录,配合n_dead_tuppg_class.reltuples来排查问题
  4. 可以配置定时任务执行VACUUM,使用VACUUM ANALYZE不仅可以清除无效数据,pg_class.reltuples也会刷新。