Postgres:"vacuum" 命令不清除死元组

Postgres: "vacuum" command does not clean up dead tuples

我们在 Amazon RDS 中有一个 postgres 数据库。最初,我们需要快速加载大量数据,所以根据best practice suggestion from Amazon关闭了autovacuum。最近我在 运行 查询时注意到一些性能问题。然后我意识到它已经很久没有吸尘了。事实证明,许多表都有很多死元组。

令人惊讶的是,即使我在某些表上手动执行 运行 vacuum 命令后,它似乎也根本没有删除这些死元组。 vacuum full 完成时间太长,通常会在一整夜后超时。

为什么 vacuum 命令不起作用?我的其他选择是什么,重启实例?

https://dba.stackexchange.com/a/77587/30035 解释了为什么没有删除所有死元组。

为了vacuum full不超时,设置statement_timeout = 0

http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_BestPractices.html#CHAP_BestPractices.PostgreSQL 建议在数据库还原时禁用 autovacuum,他们还明确建议使用它:

Important

Not running autovacuum can result in an eventual required outage to perform a much more intrusive vacuum operation.

取消所有会话并清理 table 应该有助于解决以前的死元组(关于您重启集群的建议)。但我建议您首先做的是 - 打开 autovacuum。最好控制 table 上的真空,而不是 autovacuum_vacuum_threshold 整个集群上的真空,(ALTER TABLE) 参考:https://www.postgresql.org/docs/current/static/sql-createtable.html#SQL-CREATETABLE-STORAGE-PARAMETERS

使用 VACUUM (VERBOSE) 获取有关其正在做什么及其原因的详细统计信息。

无法移除死元组的三种原因:

  1. 有一个很长的运行交易还没有关闭。你可以找到

    的坏男孩
    SELECT pid, datname, usename, state, backend_xmin
    FROM pg_stat_activity
    WHERE backend_xmin IS NOT NULL
    ORDER BY age(backend_xmin) DESC;
    

    您可以使用 pg_cancel_backend() or pg_terminate_backend().

  2. 摆脱交易
  3. 有未提交的准备事务。您可以通过

    找到它们
    SELECT gid, prepared, owner, database, transaction
    FROM pg_prepared_xacts
    ORDER BY age(transaction) DESC;
    

    用户 COMMIT PREPARED or ROLLBACK PREPARED 关闭它们。

  4. 还有replication slots没有用到。用

    找到他们
    SELECT slot_name, slot_type, database, xmin
    FROM pg_replication_slots
    ORDER BY age(xmin) DESC;
    

    使用pg_drop_replication_slot()删除未使用的复制槽。