PostgreSQL自动清理花费太长时间

时间:2020-07-13 15:01:49

标签: postgresql vacuum

我有db表,其中有大约5-6 Mn个条目,执行清理大约需要20分钟。由于此表的一个字段非常频繁地更新,因此有很多死行要处理。

据估计,根据我们当前的用户群,每天有200万个死元组。因此,清理该表既需要:

  1. 读取IO:共享内存中不存在整个表。
  2. 写IO:因为有很多条目需要更新。

什么是清理这张桌子的理想方法?我应该增加autovacuum_cost_limit来允许每次自动真空运行更多操作吗?但正如我所看到的,它将增加IOPS,这又可能会妨碍性能。目前,我有autovacuum_scale_factor = 0.2。我应该减少吗?如果我减少它,它将运行得更频繁,尽管写入IO会减少,但会导致读取IO较高的时间段。

此外,随着用户群的增加,表的大小将越来越多,并且表的大小将增加,并且真空度将不得不从磁盘读取很多内容。那么,我该怎么办?

我想到的一种解决方案:

  1. 分隔高度更新的列并创建一个单独的表。
  2. 调整参数使其更频繁地运行以减少写入IO(如上所述)。既然真空将越来越频繁地运行,如何处理更多的读取IO?
  3. 结合点2并增加RAM以减少Read IO。

一般来说,人们采用什么方法,因为我认为人们必须拥有10GB或更大的超大表,所以需要清理。

2 个答案:

答案 0 :(得分:1)

有两种方法:

  1. 为该表减少autovacuum_vacuum_cost_delay,以使自动清理变得更快。它仍然会消耗I / O,CPU和RAM。

  2. 将表的fillfactor设置为小于100的值,并确保对您经常更新的列进行索引。然后,您可以获得不需要VACUUM HOT更新

答案 1 :(得分:1)

分隔列是一种可行的策略,但对我而言是不得已的选择。 PostgreSQL已经具有很高的每行开销,并且这样做会使它增加一倍(这也可能会消除大部分好处)。另外,它会使您的查询更难看,更难以阅读,更难以维护,更容易引入错误。在最吸引人的地方是,如果对一组不包含索引的列进行仅索引扫描对您而言很重要,那么将其拆分出来可以使其余列的可见性图保持更好的状态。

为什么您要花20分钟呢?那会导致不好的事情发生吗?以这种速度,您每天可以清理这张表72次,这似乎比实际需要清理的次数要多。在v12中,autovacuum_vacuum_cost_delay的默认值下降了10倍,至2ms。默认设置的这种变化不是由v12中的代码更改引起的,而是由人们意识到,在大多数情况下,旧的默认设置对于现代硬件而言已经过时了。我将毫不费力地将更改推送到v11配置中;但我认为这样做也不会解决您的主要问题。

您实际上对正在生成的IO数量有疑问吗,还是仅仅是猜测?完成的IO大多是顺序的,但是其重要性取决于您的存储硬件。当真空发生时,您是否看到等待时间尖峰?是否按IO收费,费用太高?高IO并不是天生的问题,只有引起问题才是问题。

当前,我的autovacuum_scale_factor = 0.2。我应该减少吗? 如果我减少它,它将运行更多,尽管写入IO将 减少,但会导致阅读次数更多的时间段 IO。

更频繁地运行可能不会使您的写入IO减少很多(如果有的话)。在每次清理期间,每个带有至少一个过时的元组的表/索引页面都需要写入。仅仅为了删除一个过时的元组而写一页将比等待直到有很多过时的元组都可以通过一次写入将其删除来写更多的内容。您为每个真空度编写的内容可能要少一些,但是进行更多的真空度可以弥补这一点,并且可能远远超过弥补。