1

我有一个用例,每分钟同时在另一端插入 100 000 行,少数线程会获取这些行并将它们从我的表中删除。所以肯定会在我的表中创建很多死元组。

我的自动真空配置是

autovacuum_max_workers = 3
autovacuum_naptime = 1min
utovacuum_vacuum_scale_factor = 0.2
autovacuum_analyze_scale_factor = 0.1
autovacuum_vacuum_cost_delay = 20ms
autovacuum_vacuum_cost_limit = -1

从“pg_stat_user_tables”我可以发现自动真空正在我的表上运行,但在几个小时内我的磁盘将满(500 GB),我无法插入任何新行。

在第二次尝试时,我更改了以下配置

autovacuum_naptime = 60min
autovacuum_vacuum_cost_delay = 0

这次我的模拟和自动真空运行良好,最大磁盘大小为 180 GB。

这里我的疑问是,如果我将“autovacuum_vacuum_cost_delay”更改为零毫秒,自动真空如何释放死元组空间并 PG 重用它?如果我将值设置为 20 毫秒,为什么它不能按预期工作?

4

3 回答 3

2

这里我的疑问是,如果我将“autovacuum_vacuum_cost_delay”更改为零毫秒,自动真空如何释放死元组空间并 PG 重用它?

真空释放的空间记录在可用空间映射中,从那里分发以供将来的 INSERT 重复使用。

另一个要补充的细节是,在 9.6 中,只有在整个表本身被完全清空后才会清空可用空间映射,因此直到那时才能找到释放的空间。如果 VACUUM 由于太慢或被中断而永远无法完成,那么它释放的空间将不会被重新用于 INSERT。这在 v11 中得到了改进。

如果我将值设置为 20 毫秒,为什么它不能按预期工作?

因为真空跟不上那个值。PostgreSQL 的默认值通常只适用于较小的服务器,而您的服务器似乎并不适用。在这种情况下更改默认值是适当且可取的。请注意,在 v12 中,默认值从 20 降低到 2(其类​​型也相应地从 int 更改为 float,因此您现在可以更精确地指定值)

于 2020-08-11T16:50:03.650 回答
1

总而言之,您的应用程序创建了大量的死元组,而 autovacuum 无法跟上。可能的解决方案

  1. 这听起来更像是一个任务队列,而不是一个常规的表。也许 PostgreSQL 表不适合您的这个特定用例。请改用 RabbitMQ/Redis 等解决方案。
  2. 创建基于时间的范围分区并在旧分区为空时清除它们,同时仅在此表上禁用自动清理。如果您可以识别已处理的分区,请考虑根本不删除行并仅清除旧分区。
  3. 调整 autovacuum 设置,使其持续工作,没有任何小睡或干扰。增加maintenance_work_mem也可以帮助加速 autovacuum。也许您会发现您已经达到了硬盘驱动器的极限。在这种情况下,您将不得不优化存储,以便它能够容纳那些昂贵的INSERT++DELETE操作autovacuum
于 2020-08-11T19:06:03.663 回答
0

那么默认值是2 ms Autovacuum。所以你的20ms价值很高:

autovacuum_vacuum_cost_delay(浮点数)

"指定将在自动 VACUUM 操作中使用的成本延迟值。如果指定 -1,将使用常规的 Vacuum_cost_delay 值。如果指定此值没有单位,则以毫秒为单位。默认值为 2 毫秒。此参数只能在 postgresql.conf 文件或服务器命令行中设置;但可以通过更改表存储参数来覆盖单个表的设置。”

如此处所述真空

" Vacuum_cost_delay (浮点数)

超过成本限制时进程将休眠的时间量。如果指定此值没有单位,则以毫秒为单位。默认值为零,这将禁用基于成本的真空延迟功能。正值启用基于成本的吸尘。

当使用基于成本的清理时,vacuum_cost_delay 的适当值通常非常小,可能小于 1 毫秒。虽然 vacuum_cost_delay 可以设置为毫秒值,但在旧平台上可能无法准确测量此类延迟。在这样的平台上,将 VACUUM 的节流资源消耗增加到超过 1 毫秒时将需要更改其他真空成本参数。尽管如此,您应该将vacuum_cost_delay 保持在您的平台持续测量的范围内;大的延迟是没有帮助的。"

于 2020-08-11T15:52:37.447 回答