+-
优化PostgreSQL Autovacuum

作者:Laurenz Albe是CYBERTEC的高级顾问和支持工程师。自2006年以来,他一直在PostgreSQL上工作并为PostgreSQL做贡献。

译者:类延良,任职于瀚高基础软件股份有限公司,PostgreSQL数据库技术爱好者,10g &11g OCM,OGG认证专家。

在许多PostgreSQL数据库中,您无需考虑或担心调整autovacuum。它会在后台自动运行,并在不妨碍您的情况下进行清理。

但是有时默认配置还不够好,您必须调整autovacuum以使其正常工作。本文介绍了一些典型的问题方案,并介绍了在这些情况下的处理方法。

autovacuum的任务

有许多autovacuum的配置参数,这会使调整变得复杂。主要原因是autovacuum具有许多不同的任务。从某种意义上说,autovacuum必须解决由PostgreSQL的多版本并发控制(MVCC)实现引起的所有问题:

清理UPDATE或DELETE操作后留下的“死元组” 更新可用空间映射(free space map),以跟踪表块中的可用空间 更新仅索引扫描所需的可见性图(visibility map) “冻结”(freeze)表行,以便事务ID计数器可以安全地环绕

根据这些功能中的哪个会导致问题,您需要不同的方法来调整autovacuum。

调整autovacuum以清除死元组

最有名的autovacuum任务是清理UPDATE或DELETE操作中的死元组。如果autovacuum不能跟上清理死元组的速度,则应遵循以下三个调整步骤:

确保没有任何东西可以阻止autovacuum回收死元组
检查防止vacuum清除死元组的已知原因https://www.cybertec-postgresql.com/en/reasons-why-vacuum-wont-remove-dead-rows/罪魁祸首通常是长期事务。除非您可以消除这些障碍,否则调整autovacuum将无用。

如果您不能从根本上解决问题,则可以使用配置参数
idle_in_transaction_session_timeout使PostgreSQL终止会话,这些会话在事务中处于“idle in transaction”的时间过长。这会在客户端导致错误,但是如果您没有其他方法可以保持数据库正常运行,这可能是有道理的。同样,要解决长期运行的query,可以使用statement_timeout配置参数。

调整autovacuum以使其运行更快
如果autovacuum无法跟上清理死元组的速度,那么解决方案就是使其工作更快。这看起来似乎很明显,但是许多人陷入了使autovacuum更早开始或更频繁运行将解决问题的陷阱。

VACUUM是一项耗费资源的操作,因此默认情况下,autovacuum操作的速度故意降低。目的是使其在后台运行而不妨碍正常的数据库操作。但是,如果您的工作负载创建了很多死元组,那么您将不得不使其更具侵略性:

从autovacuum_vacuum_cost_limit默认值200开始增加(这是一种柔和的方法) 从autovacuum_vacuum_cost_delay从默认值2开始减少(在旧版本:20)毫秒(这是有效的方法)

设置autovacuum_vacuum_cost_delay为零将使autovacuum与手动VACUUM速度一样快,即尽可能快。

由于并非所有表都以相同的速度增长死元组,因此通常最好不要更改中的全局设置postgresql.conf,而要单独更改繁忙表的设置:
ALTER TABLE busy_table SET (autovacuum_vacuum_cost_delay = 1);

对表进行分区还可以帮助更快地完成工作。请参阅本文partition部分了解更多信息。

更改工作负载,以便生成更少的死元组
如果没有其他效果,则必须看到生成的死元组更少。也许将几个UPDATE合并为一行UPDATE通常,您可以使用“ HOT更新”来显着减少死元组的数量:

将表的fillfactor参数设置为小于100的值,以使INSERTs在每个块中保留一些可用空间 确保你在update语句中修改的列不是索引列

然后,任何SELECT或DML语句都可以清除死元组,而对VACUUM的需求则更少。

调整仅索引扫描的autovacuum
索引扫描的昂贵部分是查找实际的表行。如果您想要的所有列都在索引中,则完全不需要访问该表。但是在PostgreSQL中,您还必须检查一个元组是否可见,并且该信息仅存储在表中。

为了解决这个问题,PostgreSQL对每个表都有一个“可见性图”(visibility map)。如果一个表块在可见性图(visibility map)中被标记为“所有可见”,则不必访问该表以获取可见性信息。

因此,要获得真正的仅索引扫描,autovacuum必须处理表并经常更新可见性图(visibility map)。为此,如何配置autovacuum取决于查询收到的数据修改类型:

为接收UPDATEs或DELETEs的表的仅索引扫描调整autovacuum
为此,您可以减少表的存储参数autovacuum_vacuum_scale_factor,例如
ALTER TABLE mytable SET (autovacuum_vacuum_scale_factor = 0.01);

按照如上所述加快autovacuum是一个好主意。

调整仅接收INSERTs的表的仅索引扫描的autovacuum
从v13开始,这很简单:对配置参数autovacuum_vacuum_insert_scale_factor进行调整,调整方法是如上所示对autovacuum_vacuum_scale_factor的调整。

对于较旧的PostgreSQL版本,您可以做的最好方法就是降低autovacuum_freeze_max_age,最佳值取决于您使用事务id的速率,如果您每天消耗100000个事务id,并且希望每天自动清理table,则可以进行如下设置:

ALTER TABLE insert_only SET (autovacuum_freeze_max_age = 100000);

要测量事务ID消耗的速率,请在一个长的时间间隔内使用两次txid_current()函数(或者从V13开始的pg_current_xact_id()函数),然后取其差值。

调整autovacuum以避免事务回绕问题
正常时,autovacuum关心并启动一个特殊的“anti-warparound” autovacuum worker,不论一个表中最老的transaction id比autovacuum_freeze_max_age参数值更老或者一个表中的最老的multiact比autovacuum_multixact_freeze_max_age 参数值更老

确保anti-wraparound vacuum可以freeze掉所有表中的行
再次强调,你不得不确保:没有阻塞autovacuum进行freeze老元组和改进pg_database.datfrozenxid 以及pg_database.datminmxid。这些阻塞者包括:

运行时间很长的session,这些session保持一个事务处于open状态或者有临时表(autovacuum不能处理临时表) 数据损坏,这会导致所有的autovacuum worker运行失败。

为了防止数据损坏,请使用更好的硬件,并总是运行最新的PostgrSQL的次要版本。

为接收updates或者Deletes的tables调优anti-wraparound vacuum
在接收updates或者deletes的table上,你不得不做的一切是看autovacuum正在运行,并且足够快以便及时完成(参见上文)

为接收inserts的tables调优anti-wraparound vacuum
从PostgreSQL v13开始,在这种情况下没有特殊考虑,因为您也可以在此类表上定期运行autovacuum。
在此之前,仅插入表是有问题的:由于没有死元组,因此永远不会触发正常的autovacuum运行。

然后,一旦autovacuum_freeze_max_age或autovacuum_multixact_freeze_max_age超过该值,您可能会突然获得大量的autovacuum运行,从而冻结整个大表,花费很长时间并导致大量的I / O。

为避免这种情况,请减少autovacuum_freeze_max_age该表:
ALTER TABLE insert_only SET (autovacuum_freeze_max_age = 10000000);

分区
对于很大的表,建议使用分区。这样做的好处是您可以让多个autovacuum workers 并行处理多个分区,因此整个分区表的完成速度比单个autovacuum worker快。

如果您有多个分区,则应增加autovacuum_max_workers,该参数是指autovacuum workers的最大数量。

只要更新影响所有分区,分区还可以帮助清理接收大量更新的表。

调优autoanalyze
更新表统计信息是自动清理的“辅助工作”。

您知道,如果您的查询计划在手工对表执行ANALYZE后变得更好,那么自动统计信息收集将不会经常发生。

在这种情况下,您可以降低autovacuum_analyze_scale_factor以使autoanalyze更频繁地处理表:
ALTER TABLE mytable SET (autovacuum_analyze_scale_factor = 0.02);

另一种选择是不使用scale factor,而是使用set autovacuum_analyze_threshold,以便每当固定数量的行发生更改时,就计算表统计信息。

例如,要配置每当超过一百万行更改时要分析的表:

ALTER TABLE mytable SET (
autovacuum_analyze_scale_factor = 0,
autovacuum_analyze_threshold = 1000000
);

结论
根据您的特定问题和PostgreSQL版本,有不同的调整开关可以使autovacuum正确执行其工作。autovacuum的许多任务和许多配置参数并没有使它变得更容易。

如果本文中的提示还不够,请考虑寻求专业咨询
(https://www.cybertec-postgresql.com/en/services/postgresql-consulting/)

原文链接:
https://www.cybertec-postgresql.com/en/tuning-autovacuum-postgresql/

更多精彩内容,请关注以下平台、网站:

中国Postgre SQL分会官方公众号(技术文章、技术活动):
开源软件联盟PostgreSQL分会

中国Postgre SQL分会技术问答社区:
www.pgfans.cn

中国Postgre SQL分会官方网站:
www.postgresqlchina.com