你如何防止死行在 postgresql 中徘徊?

pat*_*ick 7 postgresql

我在亚马逊上有生产和暂存 RDS 实例,暂存数据是生产的直接副本,因此两个实例都有重复的数据。

做一个EXPLAIN ANALYZE SELECT * from my_table WHERE my_col=true;结果是:

Seq Scan on my_table (cost=0.00..142,775.73 rows=1 width=1,436) (actual time=18,170.294..18,170.294 rows=0 loops=1) Filter: my_col Rows Removed by Filter: 360275
Run Code Online (Sandbox Code Playgroud)

在生产中,它是:

Seq Scan on my_table (cost=0.00..62,145.88 rows=1 width=1,450) (actual time=282.487..282.487 rows=0 loops=1) Filter: my_col Rows Removed by Filter: 366442
Run Code Online (Sandbox Code Playgroud)

跑步时 select pg_total_relation_size('my_table'::regclass);

我发现舞台的大小几乎是制作的两倍。从我读过的内容来看,我看到 postgresql 的 MVCC 对此负责,因为它保留了多个版本的行。我手动运行VACUUM FULL,然后看到 staging 的大小已经减少了 2/3。现在运行相同的解释分析显示:

Seq Scan on my_table  (cost=0.00..56094.75 rows=1 width=1436) (actual time=1987.340..1987.340 rows=0 loops=1) Filter: my_col Rows Removed by Filter: 360287 Total runtime: 1987.547 ms
Run Code Online (Sandbox Code Playgroud)

这很好——但我不明白的是,文档表明自动吸尘器应该启动并清理这些死行,但显然这并没有发生。

我读过好几个地方谈论“不要让索引膨胀”,但我不太明白 1) 索引如何膨胀,以及 2) 如何防止索引膨胀。

我怎样才能防止将来再次发生这种情况?

更新

这是我的 autovacuum 设置:

                name                 |  setting  | unit |  category  |                                        short_desc                                         | extra_desc |  context   | vartype | source  |  min_val  |  max_val   | enumvals | boot_val  | reset_val | sourcefile | sourceline
-------------------------------------+-----------+------+------------+-------------------------------------------------------------------------------------------+------------+------------+---------+---------+-----------+------------+----------+-----------+-----------+------------+------------
 autovacuum                          | on        |      | Autovacuum | Starts the autovacuum subprocess.                                                         |            | sighup     | bool    | default |           |            |          | on        | on        |            |
 autovacuum_analyze_scale_factor     | 0.1       |      | Autovacuum | Number of tuple inserts, updates, or deletes prior to analyze as a fraction of reltuples. |            | sighup     | real    | default | 0         | 100        |          | 0.1       | 0.1       |            |
 autovacuum_analyze_threshold        | 50        |      | Autovacuum | Minimum number of tuple inserts, updates, or deletes prior to analyze.                    |            | sighup     | integer | default | 0         | 2147483647 |          | 50        | 50        |            |
 autovacuum_freeze_max_age           | 200000000 |      | Autovacuum | Age at which to autovacuum a table to prevent transaction ID wraparound.                  |            | postmaster | integer | default | 100000000 | 2000000000 |          | 200000000 | 200000000 |            |
 autovacuum_max_workers              | 3         |      | Autovacuum | Sets the maximum number of simultaneously running autovacuum worker processes.            |            | postmaster | integer | default | 1         | 8388607    |          | 3         | 3         |            |
 autovacuum_multixact_freeze_max_age | 400000000 |      | Autovacuum | Multixact age at which to autovacuum a table to prevent multixact wraparound.             |            | postmaster | integer | default | 10000000  | 2000000000 |          | 400000000 | 400000000 |            |
 autovacuum_naptime                  | 60        | s    | Autovacuum | Time to sleep between autovacuum runs.                                                    |            | sighup     | integer | default | 1         | 2147483    |          | 60        | 60        |            |
 autovacuum_vacuum_cost_delay        | 20        | ms   | Autovacuum | Vacuum cost delay in milliseconds, for autovacuum.                                        |            | sighup     | integer | default | -1        | 100        |          | 20        | 20        |            |
 autovacuum_vacuum_cost_limit        | -1        |      | Autovacuum | Vacuum cost amount available before napping, for autovacuum.                              |            | sighup     | integer | default | -1        | 10000      |          | -1        | -1        |            |
 autovacuum_vacuum_scale_factor      | 0.2       |      | Autovacuum | Number of tuple updates or deletes prior to vacuum as a fraction of reltuples.            |            | sighup     | real    | default | 0         | 100        |          | 0.2       | 0.2       |            |
 autovacuum_vacuum_threshold         | 50        |      | Autovacuum | Minimum number of tuple updates or deletes prior to vacuum.                               |            | sighup     | integer | default | 0         | 2147483647 |          | 50        | 50        |            |
Run Code Online (Sandbox Code Playgroud)

kha*_*son 5

自动清理功能最终应该能够清理它(假设您没有禁用它),但它可能不会足够快地完成您的目的。有许多设置可以控制自动清理以及如何/何时完成,您可能会感兴趣:此处此处

对于高流失率的表尤其如此。也就是说,有大量插入和删除的表。长时间运行和空闲的事务也可能是这里的一个因素,因为MVCC将启动并阻止死元组被回收。手动执行 a 释放死元组的事实VACUUM表明,您的情况并非如此,而且可能是前一个问题。

一般来说,不建议执行 a 操作VACUUM FULL,因为这会导致排他表锁,特别是当表中的大多数行已被更新/删除时。

来自文档

不建议日常使用 FULL 选项,但在特殊情况下可能有用。一个示例是,当您删除或更新了表中的大部分行并希望该表物理收缩以占用更少的磁盘空间并允许更快的表扫描时。VACUUM FULL 通常比普通 VACUUM 更能缩小表。

您的使用模式是否属于这种情况?您确实提到涉及“直接复制”,但尚不清楚具体是如何完成的。

我曾经遇到过高流失率表的情况,其中默认的自动真空率还不够,甚至相对少量的死元组也会极大地影响查询速度(这是在一个经常查询的大表中,并且在哪里)查询需要非常快,因此受死元组的影响很大)。

为了解决这个问题,我VACUUM ANALYZE在一个设置为每 5 分钟运行一次的 cron 作业中设置了一个表手册(这样它既可以释放元组,又可以通过更新统计信息来帮助查询规划器)。由于没有那么多死元组,所以速度VACUUM相当快,并且不断的清理使死元组数量保持足够低,以便保持对该表的快速查询。

编辑回应OP的评论:

VACUUM 文档中,它说:

VACUUM 回收死元组占用的存储空间

然后医生说(强调我的):

VACUUM ANALYZE 对每个选定的表执行 VACUUM,然后执行 ANALYZE。这是日常维护脚本的便捷组合形式。有关其处理的更多详细信息,请参阅 ANALYZE。

所以它肯定会回收死元组。