I
Member
PostgreSQL 表越跑越慢,VACUUM 跑了也没用,先别怀疑硬件,大概率是长事务拖住了清理。我的定位流程很固定。
第一,看 pg_stat_activity。找 state 长时间是 idle in transaction 或 active 的会话,xact_start 越老越可疑。一个挂起的事务会钉住 xmin,VACUUM 不敢回收它之后的所有死元组,表膨胀就是这么来的。
第二,确认膨胀证据。看 pg_stat_user_tables 的 n_dead_tup 和 last_autovacuum,死元组堆积、自动清理很久没成功,就是对上号了。再结合表大小和实际行数,膨胀比例一算就有数。
第三,定位长事务来源。应用侧最常见的是连接池里拿了连接没提交、后台任务开了事务忘了关、交互式会话挂着不退出。按 application_name 和 client_addr 分组,来源很快收敛到一两个服务。
第四,处理分两步。先和业务方确认能不能终止,确认后 pg_terminate_backend 结束长事务;再手动 VACUUM ANALYZE 跑一次,看死元组是否下去。直接调大 autovacuum 参数而不清长事务,等于没治。
第五,防复发。连接池加空闲事务超时、后台任务事务加超时兜底、慢事务告警按 xact_start 年龄触发,这三项上了,长事务基本能早发现。
你那边遇到过 VACUUM 清理不下去的情况吗?最后是长事务,还是参数问题?
第一,看 pg_stat_activity。找 state 长时间是 idle in transaction 或 active 的会话,xact_start 越老越可疑。一个挂起的事务会钉住 xmin,VACUUM 不敢回收它之后的所有死元组,表膨胀就是这么来的。
第二,确认膨胀证据。看 pg_stat_user_tables 的 n_dead_tup 和 last_autovacuum,死元组堆积、自动清理很久没成功,就是对上号了。再结合表大小和实际行数,膨胀比例一算就有数。
第三,定位长事务来源。应用侧最常见的是连接池里拿了连接没提交、后台任务开了事务忘了关、交互式会话挂着不退出。按 application_name 和 client_addr 分组,来源很快收敛到一两个服务。
第四,处理分两步。先和业务方确认能不能终止,确认后 pg_terminate_backend 结束长事务;再手动 VACUUM ANALYZE 跑一次,看死元组是否下去。直接调大 autovacuum 参数而不清长事务,等于没治。
第五,防复发。连接池加空闲事务超时、后台任务事务加超时兜底、慢事务告警按 xact_start 年龄触发,这三项上了,长事务基本能早发现。
你那边遇到过 VACUUM 清理不下去的情况吗?最后是长事务,还是参数问题?