解决 RDS for PostgreSQL 中的真空性能问题 - Amazon Relational Database Service
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

解决 RDS for PostgreSQL 中的真空性能问题

本节讨论经常导致真空性能变慢的因素以及如何解决这些问题。

清理大型索引

VACUUM 按以下阶段顺序运行:初始化、堆扫描、索引和堆真空清理、索引清理、堆截断和最终清理。在堆扫描期间,该过程修剪页面、整理碎片并冻结它们。完成堆扫描后,VACUUM 将清理索引,将空页返回到操作系统,并执行最终的清理任务,例如对空闲空间映射表执行真空清理和更新统计信息。

对索引执行真空清理操作时,如果 maintenance_work_mem(或 autovacuum_work_mem)不足以处理索引,则可能需要多次扫描。在 PostgreSQL 16 及更早版本中,用于存储无效元组 ID 存在 1 GB 内存限制,对于大型索引通常需要多次扫描。PostgreSQL 17 引入了 TidStore,这会动态分配内存,而不是使用单一分配数组。此功能消除了 1 GB 限制,可以更高效地利用内存,并减少了每次索引操作中进行多次索引扫描的需求。

在 PostgreSQL 17 中,对于大型索引,如果可用内存无法一次性容纳整个索引的处理需求,那么仍可能需要多次扫描。通常,更大的索引往往包含更多需要多次扫描的无效元组。

检测缓慢的 vacuum 操作

postgres_get_av_diag() 函数可以检测 vacuum 操作何时因内存不足而运行缓慢。有关此函数的更多信息,请参阅在 RDS for PostgreSQL 中安装 autovacuum 监控和诊断工具

当可用内存不足以一次性完成索引 vacuum 时,postgres_get_av_diag() 函数会发出以下通知。

rds_tools 1.8

NOTICE: Your database is currently running aggressive vacuum to prevent wraparound and it might be slow.
NOTICE: The current setting of autovacuum_work_mem is "XXX" and might not be sufficient. Consider increasing the setting, and if necessary, scaling up the Amazon RDS instance class for more memory. 
        Additionally, review the possibility of manual vacuum with exclusion of indexes using (VACUUM (INDEX_CLEANUP FALSE, VERBOSE TRUE) table_name;).

rds_tools 1.9

NOTICE: Your database is currently running aggressive vacuum to prevent wraparound and it might be slow.
NOTICE: The current setting of autovacuum_work_mem is XX might not be sufficient. Consider increasing the setting to XXX, and if necessary, scaling up the RDS instance class for more 
        memory. The suggested value is an estimate based on the current number of dead tuples for the table being vacuumed, which might not fully reflect the latest state. Additionally, review the possibility of manual 
        vacuum with exclusion of indexes using (VACUUM (INDEX_CLEANUP FALSE, VERBOSE TRUE) table_name;). For more information, see 
        Working with PostgreSQL autovacuum in the Amazon Amazon RDS User Guide
        .
注意

postgres_get_av_diag() 函数依靠 pg_stat_all_tables.n_dead_tup 来估计索引清理所需的内存量。

postgres_get_av_diag() 函数识别出由于 autovacuum_work_mem 不足而需要多次索引扫描的慢速 vacuum 操作时,它将生成以下消息:

NOTICE: Your vacuum is performing multiple index scans due to insufficient autovacuum_work_mem:XXX for index vacuuming. 
        For more information, see Working with PostgreSQL autovacuum in the Amazon Amazon RDS User Guide.

指南

您可以使用手动 VACUUM FREEZE 应用以下解决方法来加快表的冻结速度。

增加用于清理的内存

正如 postgres_get_av_diag() 函数所建议的那样,建议增加 autovacuum_work_mem 参数以解决实例级别的潜在内存限制问题。虽然 autovacuum_work_mem 是一个动态参数,但请务必注意,要使新的内存设置生效,自动真空进程守护程序需要重新启动其工作线程。要实现这一点,请执行以下操作:

  1. 确认新设置已落实到位。

  2. 终止当前运行自动真空的进程。

这种方法可确保将调整后的内存分配应用于新的自动真空操作。

为了获得更直接的结果,请考虑在会话中手动执行 VACUUM FREEZE 操作,并增加 maintenance_work_mem 设置:

SET maintenance_work_mem TO '1GB'; VACUUM FREEZE VERBOSE table_name;

如果您使用的是 Amazon RDS,并且发现需要额外的内存来支持更高的 maintenance_work_memautovacuum_work_mem 值,请考虑升级到具有更多内存的实例类。这样可以提供必要的资源来增强手动和自动清理操作,从而提高整体真空和数据库性能。

禁用 INDEX_CLEANUP

PostgreSQL 版本 12 及更高版本中的手动 VACUUM 允许跳过索引清理阶段,而 PostgreSQL 版本 14 及更高版本中的紧急自动真空会根据 vacuum_failsafe_age 参数自动执行此操作。

警告

跳过索引清理会导致索引膨胀并对查询性能产生负面影响。为了缓解这种情况,可以考虑在维护时段内对受影响的索引重建索引或清理受影响的索引。

有关处理大型索引的更多指导,请参阅使用大型索引管理 autovacuum 中的文档。

并行索引清理

从 PostgreSQL 13 开始,默认情况下,可以使用手动 VACUUM 并行对索引进行清理,并为每个索引分配一个真空工件进程。但是,要使 PostgreSQL 确定真空操作是否符合并行执行的条件,必须满足特定标准:

  • 必须至少有两个索引。

  • max_parallel_maintenance_workers 参数应至少设置为 2。

  • 索引大小必须超过 min_parallel_index_scan_size 限制,默认为 512 KB。

您可以根据 Amazon RDS 实例上可用的 vCPU 数量和表上的索引数量来调整 max_parallel_maintenance_workers 设置,以优化清理周转时间。

有关更多信息,请参阅 Parallel vacuuming in Amazon RDS for PostgreSQL and Amazon Aurora PostgreSQL

需要清理的表或数据库太多

如 PostgreSQL 的自动真空进程守护程序文档中所述,自动真空进程守护程序通过多个进程运行。这包括一个持久性自动真空启动程序,负责为系统中的每个数据库启动自动真空工件进程。该启动程序安排这些工件大约每个数据库每 autovacuum_naptime 秒启动一次。

对于“N”个数据库,大约每 [autovacuum_naptime/N 秒] 就会有一个新工件开始工作。但是,并发工件的总数受 autovacuum_max_workers 设置的限制。如果需要清理的数据库或表的数量超过此限制,则一旦有工件可用,就会立即处理下一个数据库或表。

当许多大型表或数据库需要同时执行清理操作时,所有可用的自动真空工件可能会长时间被占用,从而会延迟其他表和数据库的维护。在事务速率较高的环境中,此瓶颈可能会迅速升级,并可能导致 Amazon RDS 实例中出现重叠真空问题。

postgres_get_av_diag() 检测到大量表或数据库时,它会提供以下建议:

NOTICE: Your database is currently running aggressive vacuum to prevent wraparound and it might be slow.
NOTICE: The current setting of autovacuum_max_workers:3 might not be sufficient. Consider increasing the setting and, if necessary, consider scaling up the Amazon RDS instance class for more workers.

指南

增加 autovacuum_max_workers

为了加快清理速度,我们建议调整 autovacuum_max_workers 参数以允许更多并发自动真空工件。如果性能瓶颈仍然存在,请考虑将 Amazon RDS 实例扩展到具有更多 vCPU 的类,这样可以进一步提高并行处理能力。

正在运行积极真空(以防止重叠)

PostgreSQL 中数据库(MaximumUsedTransactionIDs)的龄期仅会在成功完成积极真空(以防止重叠)时减少。在此真空结束之前,龄期将继续增加,具体取决于事务速率。

postgres_get_av_diag() 函数在检测到积极真空时会生成以下 NOTICE。但是,只有在真空处于活动状态至少两分钟后,它才会触发此输出。

NOTICE: Your database is currently running aggressive vacuum to prevent wraparound, monitor autovacuum performance.

有关积极真空的更多信息,请参阅当积极真空已经在运行时

您可以使用以下查询验证是否正在进行主动清理:

SELECT a.xact_start AS start_time, v.datname "database", a.query, a.wait_event, v.pid, v.phase, v.relid::regclass, pg_size_pretty(pg_relation_size(v.relid)) AS heap_size, ( SELECT string_agg(pg_size_pretty(pg_relation_size(i.indexrelid)) || ':' || i.indexrelid::regclass || chr(10), ', ') FROM pg_index i WHERE i.indrelid = v.relid ) AS index_sizes, trunc(v.heap_blks_scanned * 100 / NULLIF(v.heap_blks_total, 0)) AS step1_scan_pct, v.index_vacuum_count || '/' || ( SELECT count(*) FROM pg_index i WHERE i.indrelid = v.relid ) AS step2_vacuum_indexes, trunc(v.heap_blks_vacuumed * 100 / NULLIF(v.heap_blks_total, 0)) AS step3_vacuum_pct, age(CURRENT_TIMESTAMP, a.xact_start) AS total_time_spent_sofar FROM pg_stat_activity a INNER JOIN pg_stat_progress_vacuum v ON v.pid = a.pid;

您可以通过检查输出中的查询列来确定这是否为积极真空(以防止重叠)。“防止重叠”一词表示这是一个积极真空。

query | autovacuum: VACUUM public.t3 (to prevent wraparound)

例如,假设您有一个事务龄期为 10 亿的拦截器,还有一个需要积极真空的表,以防止在相同的事务龄期出现重叠。此外,在事务龄期为 7.5 亿时,还有另一个拦截器。在事务龄期为 10 亿时清除拦截器后,事务龄期不会立即下降到 7.5 亿。它将保持较高的状态,直到需要积极真空或任何龄期超过 7.5 亿的事务完成为止。在此期间,PostgreSQL 集群的事务龄期将持续提高。真空过程完成后,事务龄期将降至 7.5 亿,但在进一步的清理完成之前,事务龄期将再次开始增加。只要这些条件仍然存在,此循环就会继续,直到事务龄期最终下降到为您的 Amazon RDS 实例配置的级别(由 autovacuum_freeze_max_age 指定)。