

# 在 Amazon Aurora PostgreSQL 上使用 PostgreSQL autovacuum
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum"></a>

我们强烈建议您使用 Autovacuum 功能来保持 PostgreSQL 数据库实例正常运行。Autovacuum 自动启动 VACUUM 和 ANALYZE 命令。它会检查包含大量插入的、更新的或删除的元组的表。进行此检查后，它会通过从 PostgreSQL 数据库中删除过时的数据或元组来回收存储。

在使用任何默认 PostgreSQL 数据库参数组创建的 Aurora PostgreSQL 数据库实例上，会默认启用 autovacuum。默认情况下，还会设置与 Autovacuum 功能关联的其他配置参数。这些默认值是通用值，因此可以针对特定工作负载优化与 Autovacuum 功能关联的某些参数。

在下文中，您可以了解有关 autovacuum 功能以及如何为 Aurora PostgreSQL 数据库实例优化其部分参数的更多信息。

**Topics**
+ [

## 为 Autovacuum 分配内存
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum.WorkMemory)
+ [

## 减少事务 ID 重叠的可能性
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AdaptiveAutoVacuuming)
+ [

# 确定数据库中的表是否需要 vacuum 操作
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.NeedVacuuming.md)
+ [

# 确定哪些表当前符合 Autovacuum 条件
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.EligibleTables.md)
+ [

# 确定 Autovacuum 当前是否正在运行以及运行时长
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AutovacuumRunning.md)
+ [

# 执行手动 vacuum 冻结
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.VacuumFreeze.md)
+ [

# 在 Autovacuum 正在运行时重新为表建立索引
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.Reindexing.md)
+ [

# 使用大型索引管理 autovacuum
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.LargeIndexes.md)
+ [

# 其他影响 Autovacuum 的参数
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.OtherParms.md)
+ [

# 设置表级别 Autovacuum 参数
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.TableParameters.md)
+ [

# 记录 autovacuum 和 vacuum 活动
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.Logging.md)
+ [

# 了解对无效数据库使用 autovacuum 的行为
](appendix.postgresql.commondbatasks.autovacuumbehavior.md)
+ [

# 识别并解决 Aurora PostgreSQL 中的积极真空拦截器
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.md)

## 为 Autovacuum 分配内存
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.WorkMemory"></a>

影响Autovacuum 性能的最重要参数之一是 [https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-AUTOVACUUM-WORK-MEM](https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-AUTOVACUUM-WORK-MEM) 参数。在 Aurora PostgreSQL 版本 14 及更早版本中，`autovacuum_work_mem` 参数设置为 -1，表示改用 `maintenance_work_mem` 的设置。对于所有其它版本，`autovacuum_work_mem` 由 GREATEST(\$1DBInstanceClassMemory/32768\$1, 65536) 决定。

手动 vacuum 操作始终使用 `maintenance_work_mem` 设置，默认设置为 GREATEST(\$1DBInstanceClassMemory/63963136\$11024\$1, 65536)，也可以使用 `SET` 命令在会话级别对其进行调整，以进行更有针对性的手动 `VACUUM` 操作。

`autovacuum_work_mem` 确定 autovacuum 在对索引执行 vacuum 操作时，用于容纳无效元组 (`pg_stat_all_tables.n_dead_tup`) 的标识符的内存。

当执行计算以确定 `autovacuum_work_mem` 参数的值时，请注意以下事项：
+ 如果将此参数设得过低，则 vacuum 过程可能必须扫描表多次才能完成其工作。此类多次扫描可能会对性能产生负面影响。对于较大的实例，将 `maintenance_work_mem` 或 `autovacuum_work_mem` 设置为至少 1 GB，可以提高对包含大量无效元组的表执行 vacuum 操作的性能。但是，在 PostgreSQL 版本 16 及更早版本中，vacuum 的内存使用量上限为 1 GB，这足以单次处理大约 1.79 亿个无效元组。如果表的无效元组比这更多，vacuum 将需要多次遍历表的索引，从而显著增加所需的时间。从 PostgreSQL 版本 17 开始，没有 1 GB 的限制，自动真空可以使用基数树处理超过 1.79 亿个元组。

  元组标识符的大小为 6 个字节。要估算对表的索引执行 vacuum 操作所需的内存，请查询 `pg_stat_all_tables.n_dead_tup` 来找到无效元组的数量，然后将该数字乘以 6，以确定单次对索引执行 vacuum 操作所需的内存。您可以使用以下查询：

  ```
  SELECT
      relname AS table_name,
      n_dead_tup,
      pg_size_pretty(n_dead_tup * 6) AS estimated_memory
  FROM
      pg_stat_all_tables
  WHERE
      relname = 'name_of_the_table';
  ```
+ `autovacuum_work_mem` 参数可与 `autovacuum_max_workers` 参数结合使用。`autovacuum_max_workers` 中的每个工作进程均可使用您分配的内存。如果您有多个小型表，请分配更多的 `autovacuum_max_workers` 和更少的 `autovacuum_work_mem`。如果您拥有大型表（大于 100 GB），请分配更多内存和更少的工作进程。您需要分配有足够的内存才能对最大的表成功完成操作。因此，请确保工作进程和内存的组合等于要分配的总内存。

## 减少事务 ID 重叠的可能性
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AdaptiveAutoVacuuming"></a>

在一些情况下，与 Autovacuum 相关的参数组设置可能不够积极，无法阻止事务 ID 重叠。为解决此问题，Aurora PostgreSQL 提供了自动调整 Autovacuum 参数值的机制。*适应性 autovacuum* 是 Aurora PostgreSQL 的一项功能。在 PostgreSQL 文档中找到了 [TransactionID 重叠](https://www.postgresql.org/docs/current/static/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND)的详细说明。

默认情况下，动态参数 `rds.adaptive_autovacuum` 设置为 ON 的 Aurora PostgreSQL 实例启用适应性 autovacuum。强烈建议您保持启用此选项。不过，要关闭适应性 Autovacuum 参数优化，请将 `rds.adaptive_autovacuum` 参数设置为 0 或 OFF。

即使在 Aurora 优化 Autovacuum 参数时，仍可能出现事务 ID 重叠。鼓励您为事务 ID 重叠实施 Amazon CloudWatch 警报。有关更多信息，请参阅 AWS 数据库博客上的贴子[在 RDS for PostgreSQL 中为事务 ID 重叠实施预警系统](https://aws.amazon.com/blogs/database/implement-an-early-warning-system-for-transaction-id-wraparound-in-amazon-rds-for-postgresql/)。

启用适应性 autovacuum 参数优化后，当 CloudWatch 指标 `MaximumUsedTransactionIDs` 达到 `autovacuum_freeze_max_age` 参数值或 500000000 中的较大值时，Amazon RDS 将开始调整 autovacuum 参数。

如果表继续倾向于事务 ID 重叠，则 Amazon RDS 将继续调整 autovacuum 的参数。其中每次调整都会将更多资源专用于 Autovacuum 以避免重叠。Amazon RDS 更新以下与 Autovacuum 相关的参数：
+ [Autovacuum\$1vacuum\$1cost\$1delay](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-VACUUM-COST-DELAY)
+ [ Autovacuum\$1vacuum\$1cost\$1limit](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-VACUUM-COST-LIMIT)
+  [https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-AUTOVACUUM-WORK-MEM](https://www.postgresql.org/docs/current/runtime-config-resource.html#GUC-AUTOVACUUM-WORK-MEM) 
+  [Autovacuum\$1naptime](https://www.postgresql.org/docs/current/runtime-config-autovacuum.html#GUC-AUTOVACUUM-NAPTIME) 

仅当新值使 Autovacuum 更积极时，RDS 才会修改这些参数。在数据库实例上的内存中修改参数。不会更改参数组中的值。要查看当前内存中的设置，请使用 PostgreSQL [SHOW](https://www.postgresql.org/docs/current/sql-show.html) SQL 命令。

当 Amazon RDS 修改其中任何 autovacuum 参数时，它会为受影响的数据库实例生成事件。此事件在 AWS 管理控制台 上和通过 Amazon RDS API 显示。在 `MaximumUsedTransactionIDs` CloudWatch 指标返回的值低于阈值后，Amazon RDS 会将内存中与 autovacuum 相关的参数重置回参数组中指定的值。然后，它会生成另一个与此更改对应的事件。

# 确定数据库中的表是否需要 vacuum 操作
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.NeedVacuuming"></a>

您可以使用以下查询显示数据库中解冻事务的数目。数据库的 `datfrozenxid` 行的 `pg_database` 列是显示在该数据库中的正常事务 ID 的下限。此列是数据库中每个表的 `relfrozenxid` 值的最小值。

```
SELECT datname, age(datfrozenxid) FROM pg_database ORDER BY age(datfrozenxid) desc limit 20;
```

例如，运行上述查询的结果可能如下所示。

```
datname    | age
mydb       | 1771757888
template0  | 1721757888
template1  | 1721757888
rdsadmin   | 1694008527
postgres   | 1693881061
(5 rows)
```

当数据库的期限达到 20 亿个事务 ID 时，事务 ID (XID) 重叠将出现，并且数据库将变成只读状态。您可以使用此查询来生成指标，并且一天可运行几次。默认情况下，将设置 Autovacuum 以确保事务期限不超过 200000000 ()。[https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-FREEZE-MAX-AGE](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-FREEZE-MAX-AGE)

示例监控策略可能类似于：
+ 将 `autovacuum_freeze_max_age` 值设置为 2 亿个事务。
+ 如果表中的解冻事务达到 5 亿个，则会触发低严重性警报。这不是一个不合理的值，但它可能指示 Autovacuum 未保持同步。
+ 如果表期限为 10 亿，这应被视为要采取操作的警报。通常，您出于性能原因，需要使期限更接近 `autovacuum_freeze_max_age`。建议您使用以下建议进行调查。
+ 如果表达到 15 亿个未执行 vacuum 操作的事务，则这会触发高严重性警报。根据数据库使用事务 ID 的频率，此警报将指示系统运行 Autovacuum 的时间不多了。在这种情况下，建议您立即解决此问题。

如果表持续违反这些阈值，请进一步修改 autovacuum 参数。默认情况下，手动使用 VACUUM（已禁用基于成本的延迟）比使用默认的 Autovacuum 更积极，但对整个系统来说也更具侵入性。

我们建议执行下列操作：
+ 了解和启用监控机制，以便您了解最早的事务的期限。

  有关创建提醒您事务 ID 重叠的过程的信息，请参阅 AWS 数据库博客帖子 [Implement an early warning system for transaction ID wraparound in Amazon RDS for PostgreSQL](https://aws.amazon.com/blogs/database/implement-an-early-warning-system-for-transaction-id-wraparound-in-amazon-rds-for-postgresql/)。
+ 对于更复杂的表，在维护时段内定期执行手动 vacuum 冻结操作，并依赖 Autovacuum。有关执行手动 vacuum 冻结的信息，请参阅[执行手动 vacuum 冻结](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.VacuumFreeze.md)。

# 确定哪些表当前符合 Autovacuum 条件
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.EligibleTables"></a>

通常，它是需要执行 vacuum 操作的一个或两个表。其 `relfrozenxid` 值大于 `autovacuum_freeze_max_age` 中的事务数的表始终是 Autovacuum 的目标。否则，如果元组数因上一个 VACUUM 超出 vacuum 阈值而变得过时，则对表执行 vacuum 操作。

[Autovacuum 阈值](https://www.postgresql.org/docs/current/static/routine-vacuuming.html#AUTOVACUUM)的定义如下：

```
Vacuum-threshold = vacuum-base-threshold + vacuum-scale-factor * number-of-tuples
```

其中，`vacuum base threshold` 为 `autovacuum_vacuum_threshold`，`vacuum scale factor` 为 `autovacuum_vacuum_scale_factor`，而 `number of tuples` 为 `pg_class.reltuples`。

在连接到数据库时，运行以下查询可查看 autovacuum 认为有资格执行 vacuum 操作的表的列表。

```
WITH vbt AS (SELECT setting AS autovacuum_vacuum_threshold FROM 
pg_settings WHERE name = 'autovacuum_vacuum_threshold'),
vsf AS (SELECT setting AS autovacuum_vacuum_scale_factor FROM 
pg_settings WHERE name = 'autovacuum_vacuum_scale_factor'), 
fma AS (SELECT setting AS autovacuum_freeze_max_age FROM pg_settings WHERE name = 'autovacuum_freeze_max_age'),
sto AS (select opt_oid, split_part(setting, '=', 1) as param,
split_part(setting, '=', 2) as value from (select oid opt_oid, unnest(reloptions) setting from pg_class) opt)
SELECT '"'||ns.nspname||'"."'||c.relname||'"' as relation,
pg_size_pretty(pg_table_size(c.oid)) as table_size,
age(relfrozenxid) as xid_age,
coalesce(cfma.value::float, autovacuum_freeze_max_age::float) autovacuum_freeze_max_age,
(coalesce(cvbt.value::float, autovacuum_vacuum_threshold::float) +
coalesce(cvsf.value::float,autovacuum_vacuum_scale_factor::float) * c.reltuples)
AS autovacuum_vacuum_tuples, n_dead_tup as dead_tuples FROM
pg_class c join pg_namespace ns on ns.oid = c.relnamespace 
join pg_stat_all_tables stat on stat.relid = c.oid join vbt on (1=1) join vsf on (1=1) join fma on (1=1)
left join sto cvbt on cvbt.param = 'autovacuum_vacuum_threshold' and c.oid = cvbt.opt_oid 
left join sto cvsf on cvsf.param = 'autovacuum_vacuum_scale_factor' and c.oid = cvsf.opt_oid
left join sto cfma on cfma.param = 'autovacuum_freeze_max_age' and c.oid = cfma.opt_oid
WHERE c.relkind = 'r' and nspname <> 'pg_catalog'
AND (age(relfrozenxid) >= coalesce(cfma.value::float, autovacuum_freeze_max_age::float)
OR coalesce(cvbt.value::float, autovacuum_vacuum_threshold::float) + 
coalesce(cvsf.value::float,autovacuum_vacuum_scale_factor::float) * 
c.reltuples <= n_dead_tup)
ORDER BY age(relfrozenxid) DESC LIMIT 50;
```

# 确定 Autovacuum 当前是否正在运行以及运行时长
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AutovacuumRunning"></a>

如果需要手动对表执行 vacuum 操作，确保确定 autovacuum 当前是否正在运行。如果它当前正在运行，则您可能需要调整参数以使其更高效地运行，或者暂时禁用 autovacuum 以便手动运行 VACUUM。

使用以下查询来确定 Autovacuum 是否正在运行、它已运行的时长以及它是否正在等待其他会话。

```
SELECT datname, usename, pid, state, wait_event, current_timestamp - xact_start AS xact_runtime, query
FROM pg_stat_activity 
WHERE upper(query) LIKE '%VACUUM%' 
ORDER BY xact_start;
```

在运行查询后，您应看到类似以下内容的输出。

```
 datname | usename  |  pid  | state  | wait_event |      xact_runtime       | query  
 --------+----------+-------+--------+------------+-------------------------+--------------------------------------------------------------------------------------------------------
 mydb    | rdsadmin | 16473 | active |            | 33 days 16:32:11.600656 | autovacuum: VACUUM ANALYZE public.mytable1 (to prevent wraparound)
 mydb    | rdsadmin | 22553 | active |            | 14 days 09:15:34.073141 | autovacuum: VACUUM ANALYZE public.mytable2 (to prevent wraparound)
 mydb    | rdsadmin | 41909 | active |            | 3 days 02:43:54.203349  | autovacuum: VACUUM ANALYZE public.mytable3
 mydb    | rdsadmin |   618 | active |            | 00:00:00                | SELECT datname, usename, pid, state, wait_event, current_timestamp - xact_start AS xact_runtime, query+
         |          |       |        |            |                         | FROM pg_stat_activity                                                                                 +
         |          |       |        |            |                         | WHERE query like '%VACUUM%'                                                                           +
         |          |       |        |            |                         | ORDER BY xact_start;                                                                                  +
```

有多个问题可能会导致长时间运行 Autovacuum 会话（即，多天）。最常见的问题是，对于表的大小或更新速率来说，设置的 [https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM](https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM) 参数值太小。

建议您使用以下公式来设置 `maintenance_work_mem` 参数值。

```
GREATEST({DBInstanceClassMemory/63963136*1024},65536)
```

短时间运行的 Autovacuum 会话还可以指示以下问题：
+ 它可以指示，对于工作负载而言，`autovacuum_max_workers` 不足。在这种情况下，您将需要指示工作线程数。
+ 它可以指示存在索引损坏（autovacuum 将发生崩溃并在同一关系上重新启动，但毫无进展）。在这种情况下，运行手动 `vacuum freeze verbose table` 以查看准确原因。

# 执行手动 vacuum 冻结
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.VacuumFreeze"></a>

您可能需要对已具有正在运行的 vacuum 进程的表执行手动 vacuum 操作。如果您已使用接近 20 亿个事务（或高于您监控的任何阈值）的期限标识表，则这会很有用。

以下步骤是指导原则，此过程存在几种变化。例如，在测试期间，假设您发现设定的 [https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM](https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM) 参数值过小，并且您需要立即对表采取措施。不过，可能您不希望此时恢复实例。通过使用前几节中的查询，您可以确定哪个表存在问题，并找到长时间运行的 Autovacuum 会话。您知道您需要更改 `maintenance_work_mem` 参数设置，但您还需要立即采取行动，对有问题的表执行 vacuum 操作。以下过程说明了在此情况下应采取的措施。

**手动执行 vacuum 冻结**

1. 打开针对包含要执行 vacuum 操作的表的数据库的两个会话。对于第二个会话，使用“screen”或其他维护会话的实用工具 (如果您的连接已中断)。

1. 在第一个会话中，获取正在表上运行的 autovacuum 会话的进程 ID (PID)。

   运行以下查询可获取 Autovacuum 会话的 PID。

   ```
   SELECT datname, usename, pid, current_timestamp - xact_start 
   AS xact_runtime, query
   FROM pg_stat_activity WHERE upper(query) LIKE '%VACUUM%' ORDER BY 
   xact_start;
   ```

1. 在第二个会话中，计算该操作所需的内存量。在此示例中，我们确定自己最多可以为该操作使用 2GB 的内存，因此，我们将当前会话的 [https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM](https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE-WORK-MEM) 设置为 2 GB。

   ```
   SET maintenance_work_mem='2 GB';
   SET
   ```

1. 在第二个会话中，为表发出 `vacuum freeze verbose` 命令。详细设置很有用，因为虽然 PostgreSQL 中当前没有进度报告，但您可以查看活动。

   ```
   \timing on
   Timing is on.
   vacuum freeze verbose pgbench_branches;
   ```

   ```
   INFO:  vacuuming "public.pgbench_branches"
   INFO:  index "pgbench_branches_pkey" now contains 50 row versions in 2 pages
   DETAIL:  0 index row versions were removed.
   0 index pages have been deleted, 0 are currently reusable.
   CPU 0.00s/0.00u sec elapsed 0.00 sec.
   INFO:  index "pgbench_branches_test_index" now contains 50 row versions in 2 pages
   DETAIL:  0 index row versions were removed.
   0 index pages have been deleted, 0 are currently reusable.
   CPU 0.00s/0.00u sec elapsed 0.00 sec.
   INFO:  "pgbench_branches": found 0 removable, 50 nonremovable row versions 
        in 43 out of 43 pages
   DETAIL:  0 dead row versions cannot be removed yet.
   There were 9347 unused item pointers.
   0 pages are entirely empty.
   CPU 0.00s/0.00u sec elapsed 0.00 sec.
   VACUUM
   Time: 2.765 ms
   ```

1. 在第一个会话中，如果 autovacuum 阻止 vacuum 会话，`pg_stat_activity` 显示 vacuum 会话的等待为 `T`。在此情况下，您需要终止 autovacuum 进程，如下所示。

   ```
   SELECT pg_terminate_backend('the_pid'); 
   ```
**注意**  
某些较低版本的 Amazon Aurora 无法使用上述命令终止 autovacuum 进程，并且会失败，显示以下错误：`ERROR: 42501: must be a superuser to terminate superuser process LOCATION: pg_terminate_backend, signalfuncs.c:227`。要查找已修补的 PostgreSQL 版本，请在 [Amazon Aurora PostgreSQL updates](https://docs.aws.amazon.com/')中搜索以下公告：  

   ```
   Allow rds_superuser to terminate backends which are not explicitly associated with a role
   ```

   此时，您的会话将开始。由于此表可能位于其工作列表中的最高位置，因此 Autovacuum 将立即重新启动。

1. 在第二个会话中启动您的 `vacuum freeze verbose` 命令，然后终止第一个会话中的 autovacuum 过程。

# 在 Autovacuum 正在运行时重新为表建立索引
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.Reindexing"></a>

如果索引已损坏，Autovacuum 将继续处理表并失败。在此情况下，如果您尝试执行手动 vacuum 操作，您将收到一条与以下内容类似的错误消息。

```
postgres=>  vacuum freeze pgbench_branches;
ERROR: index "pgbench_branches_test_index" contains unexpected 
   zero page at block 30521
HINT: Please REINDEX it.
```

当索引损坏并且 autovacuum 尝试在表上运行时，您将处理已经正在运行的 autovacuum 会话。在您发出 [REINDEX](https://www.postgresql.org/docs/current/static/sql-reindex.html) 命令时，将删除表上的排他锁。将阻止写入操作以及使用该特定索引的读取操作。

**在对表运行 Autovacuum 时重新为表建立索引**

1. 打开针对包含要执行 vacuum 操作的表的数据库的两个会话。对于第二个会话，使用“screen”或其他维护会话的实用工具 (如果您的连接已中断)。

1. 在第一个会话中，获取正在表上运行的 Autovacuum 会话的 PID。

   运行以下查询可获取 Autovacuum 会话的 PID。

   ```
   SELECT datname, usename, pid, current_timestamp - xact_start 
   AS xact_runtime, query
   FROM pg_stat_activity WHERE upper(query) like '%VACUUM%' ORDER BY 
   xact_start;
   ```

1. 在第二个会话中，发出 reindex 命令。

   ```
   \timing on
   Timing is on.
   reindex index pgbench_branches_test_index;
   REINDEX
     Time: 9.966 ms
   ```

1. 在第一个会话中，如果 autovacuum 阻止该过程，您将在 `pg_stat_activity` 中看到 vacuum 会话的等待为“T”。在此情况下，您将终止 autovacuum 过程。

   ```
   SELECT pg_terminate_backend('the_pid');
   ```

   此时，您的会话将开始。由于此表可能位于其工作列表中的最高位置，因此，了解 Autovacuum 将立即重新启动很重要。

1. 在第二个会话中启动您的命令，然后终止第一个会话中的 autovacuum 过程。

# 使用大型索引管理 autovacuum
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.LargeIndexes"></a>

作为其操作的一部分，在对表运行 *autovacuum* 时会执行多个 [vacuum 阶段](https://www.postgresql.org/docs/current/progress-reporting.html#VACUUM-PHASES)。在清理表之前，首先对所有索引执行 vacuum 操作。删除多个大型索引时，此阶段会消耗大量的时间和资源。因此，作为最佳实践，请务必控制表上的索引数量并消除未使用的索引。

对于此过程，请先检查总体索引大小。然后，确定是否存在可以删除的潜在未使用索引，如以下示例所示。

**检查表及其索引的大小**

```
postgres=> select pg_size_pretty(pg_relation_size('pgbench_accounts'));
pg_size_pretty
6404 MB
(1 row)
```

```
postgres=> select pg_size_pretty(pg_indexes_size('pgbench_accounts'));
pg_size_pretty
11 GB
(1 row)
```

在此示例中，索引的大小大于表的大小。这种差异可能会导致性能问题，因为索引膨胀或未使用，这会影响 autovacuum 以及插入操作。

**检查是否有未使用的索引**

使用 [https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-ALL-INDEXES-VIEW](https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-ALL-INDEXES-VIEW) 视图，您可以检查 `idx_scan` 列使用索引的频率。在以下示例中，未使用索引的 `idx_scan` 值为 `0`。

```
postgres=> select * from pg_stat_user_indexes where relname = 'pgbench_accounts' order by idx_scan desc;
    
relid  | indexrelid | schemaname | relname          | indexrelname          | idx_scan | idx_tup_read | idx_tup_fetch
-------+------------+------------+------------------+-----------------------+----------+--------------+---------------
16433  | 16454      | public     | pgbench_accounts | index_f               | 6        | 6            | 0
16433  | 16450      | public     | pgbench_accounts | index_b               | 3        | 199999       | 0
16433  | 16447      | public     | pgbench_accounts | pgbench_accounts_pkey | 0        | 0            | 0
16433  | 16452      | public     | pgbench_accounts | index_d               | 0        | 0            | 0
16433  | 16453      | public     | pgbench_accounts | index_e               | 0        | 0            | 0
16433  | 16451      | public     | pgbench_accounts | index_c               | 0        | 0            | 0
16433  | 16449      | public     | pgbench_accounts | index_a               | 0        | 0            | 0
(7 rows)
```

```
postgres=> select schemaname, relname, indexrelname, idx_scan from pg_stat_user_indexes where relname = 'pgbench_accounts' order by idx_scan desc;
    
schemaname  | relname          | indexrelname          | idx_scan
------------+------------------+-----------------------+----------
public      | pgbench_accounts | index_f               | 6
public      | pgbench_accounts | index_b               | 3
public      | pgbench_accounts | pgbench_accounts_pkey | 0
public      | pgbench_accounts | index_d               | 0
public      | pgbench_accounts | index_e               | 0
public      | pgbench_accounts | index_c               | 0
public      | pgbench_accounts | index_a               | 0
(7 rows)
```

**注意**  
这些统计数据自统计数据重置之时起开始递增。假设您的索引仅用于业务季度末或仅用于特定报告。自从统计数据重置后，此索引可能就没有使用过。有关更多信息，请参阅[统计数据函数](https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-STATS-FUNCTIONS)。用于强制唯一性的索引不会执行扫描，也不应被标识为未使用的索引。要识别未使用的索引，您应该对应用程序及其查询有深入的了解。

要检查数据库上次重置统计数据的时间，请使用 [ https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-DATABASE-VIEW]( https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-DATABASE-VIEW)

```
postgres=> select datname, stats_reset from pg_stat_database where datname = 'postgres';
    
datname   | stats_reset
----------+-------------------------------
postgres  | 2022-11-17 08:58:11.427224+00
(1 row)
```

## 尽快对表执行 vacuum 操作
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.LargeIndexes.Executing"></a>

**RDS for PostgreSQL 12 及更高版本**

如果大型表中的索引过多，则您的数据库实例可能接近事务 ID 重叠（XID），也就是 XID 计数器变为零时。如果不进行检查，这种情况可能导致数据丢失。但是，您可以在不清理索引的情况下快速对表执行 vacuum 操作。在 RDS for PostgreSQL 12 及更高版本中，可以将 VACUUM 与 [https://www.postgresql.org/docs/current/sql-vacuum.html](https://www.postgresql.org/docs/current/sql-vacuum.html) 子句结合使用。

```
postgres=> VACUUM (INDEX_CLEANUP FALSE, VERBOSE TRUE) pgbench_accounts;
        
INFO: vacuuming "public.pgbench_accounts"
INFO: table "pgbench_accounts": found 0 removable, 8 nonremovable row versions in 1 out of 819673 pages
DETAIL: 0 dead row versions cannot be removed yet, oldest xmin: 7517
Skipped 0 pages due to buffer pins, 0 frozen pages.
CPU: user: 0.01 s, system: 0.00 s, elapsed: 0.01 s.
```

如果 autovacuum 会话已在运行，则必须将其终止才能开始手动 VACUUM。有关执行手动 vacuum 冻结的信息，请参阅[执行手动 vacuum 冻结](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.VacuumFreeze.md)。

**注意**  
定期跳过索引清理会导致索引膨胀，这会降低扫描性能。索引保留死行，而表保留死行指针。因此，`pg_stat_all_tables.n_dead_tup` 会一直增加，直到 autovacuum 或带有索引清理功能的手动 VACUUM 运行。作为最佳实践，请仅使用此过程来防止事务 ID 重叠。

**RDS for PostgreSQL 11 及更低版本**

但是，在 RDS for PostgreSQL 11 及更低版本中，让 vacuum 过程更快地完成的唯一方法是减少表上的索引数量。删除索引可能会影响查询计划。我们建议您先删除未使用的索引，然后在 XID 重叠非常接近时删除索引。vacuum 过程完成后，您可以重新创建这些索引。

# 其他影响 Autovacuum 的参数
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.OtherParms"></a>

以下查询将显示直接影响 Autovacuum 及其行为的一些参数的值。PostgreSQL 文档中完整介绍了 [Autovacuum 参数](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html)。

```
SELECT name, setting, unit, short_desc
FROM pg_settings
WHERE name IN (
'autovacuum_max_workers',
'autovacuum_analyze_scale_factor',
'autovacuum_naptime',
'autovacuum_analyze_threshold',
'autovacuum_analyze_scale_factor',
'autovacuum_vacuum_threshold',
'autovacuum_vacuum_scale_factor',
'autovacuum_vacuum_threshold',
'autovacuum_vacuum_cost_delay',
'autovacuum_vacuum_cost_limit',
'vacuum_cost_limit',
'autovacuum_freeze_max_age',
'maintenance_work_mem',
'vacuum_freeze_min_age');
```

所有这些参数都会影响 Autovacuum，其中一些最重要的参数为：
+ [maintenance\$1work\$1mem](https://www.postgresql.org/docs/current/static/runtime-config-resource.html#GUC-MAINTENANCE_WORK_MEM)
+ [Autovacuum\$1freeze\$1max\$1age](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-FREEZE-MAX-AGE)
+ [Autovacuum\$1max\$1workers](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-MAX-WORKERS)
+ [Autovacuum\$1vacuum\$1cost\$1delay](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-VACUUM-COST-DELAY)
+ [ Autovacuum\$1vacuum\$1cost\$1limit](https://www.postgresql.org/docs/current/static/runtime-config-autovacuum.html#GUC-AUTOVACUUM-VACUUM-COST-LIMIT)

# 设置表级别 Autovacuum 参数
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.TableParameters"></a>

您可以在表级别设置与 autovacuum 相关的[存储参数](https://www.postgresql.org/docs/current/static/sql-createtable.html#SQL-CREATETABLE-STORAGE-PARAMETERS)，这可能优于更改整个数据库的行为。对于大型表，您可能需要设置主动设置，并且可能不希望 Autovacuum 对所有表的行为都相同。

以下查询将显示哪些表当前拥有表级别选项。

```
SELECT relname, reloptions
FROM pg_class
WHERE reloptions IS NOT null;
```

例如，对于比您的其他表大得多的表，这可能会很有用。假设您具有一个 300GB 表和另外 30 个小于 1GB 的表。在这种情况下，可以为大型表设置一些特定的参数，这样便无需更改整个系统的行为。

```
ALTER TABLE mytable set (autovacuum_vacuum_cost_delay=0);
```

这样便可通过使用系统中的更多资源来禁用此表的基于成本的 autovacuum 延迟。通常，每次达到 `autovacuum_cost_limit` 时，autovacuum 会暂停 `autovacuum_vacuum_cost_delay`。有关更多详细信息，请参阅 PostgreSQL 文档中有关[基于成本的 vacuum 操作](https://www.postgresql.org/docs/current/static/runtime-config-resource.html#RUNTIME-CONFIG-RESOURCE-VACUUM-COST)的内容。

# 记录 autovacuum 和 vacuum 活动
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum.Logging"></a>

根据 `rds.force_autovacuum_logging_level` 参数中指定的级别，有关 autovacuum 活动的信息将发送到 `postgresql.log`。以下是此参数允许的值以及该值为默认设置的 PostgreSQL 版本：
+ `disabled`（PostgreSQL 10、PostgreSQL 9.6）
+ `debug5`, `debug4`, `debug3`, `debug2`, `debug1`
+ `info`（PostgreSQL 12、PostgreSQL 11）
+ `notice`
+ `warning`（PostgreSQL 13 及更高版本）
+ `error`、日志、`fatal`、`panic`

`rds.force_autovacuum_logging_level` 与 `log_autovacuum_min_duration` 参数结合使用。`log_autovacuum_min_duration` 参数的值为阈值（以毫秒为单位），超出该值后将记录 autovacuum 操作。设置为 `-1` 不会记录任何内容，而设置 0 将记录所有操作。和 `rds.force_autovacuum_logging_level` 一样，`log_autovacuum_min_duration` 的默认值取决于版本，如下所示：
+ `10000 ms` - PostgreSQL 14、PostgreSQL 13、PostgreSQL 12 和 PostgreSQL 11 
+ `(empty)` - PostgreSQL 10 和 PostgreSQL 9.6 没有默认值

建议您将 `rds.force_autovacuum_logging_level` 设置为 `WARNING`。我们还建议您将 `log_autovacuum_min_duration` 设置为 1000 到 5000 之间的值。设置为 5000 的记录活动耗时将超过 5000 毫秒。如果由于冲突锁定或并行删除关系跳过了 autovacuum 操作，则并非 -1 的任何其他设置也会记录消息。有关更多信息，请参阅 PostgreSQL 文档中的 [Automatic Vacuuming](https://www.postgresql.org/docs/current/runtime-config-autovacuum.html)。

要对问题进行故障排除，可以将 `rds.force_autovacuum_logging_level` 参数更改为调试级别之一，从 `debug1` 到最高 `debug5` 以获取最详细的信息。我们建议您在短时间内使用调试设置，并且仅用于故障排除目的。要了解更多信息，请参阅 PostgreSQL 文档中的[何时记录](https://www.postgresql.org/docs/current/static/runtime-config-logging.html#RUNTIME-CONFIG-LOGGING-WHEN)。

**注意**  
PostgreSQL 允许 `rds_superuser` 账户查看 `pg_stat_activity` 中的 Autovacuum 会话。例如，您可识别并结束阻止命令运行或运行速度慢于手动发出的 vacuum 命令的 Autovacuum 会话。

# 了解对无效数据库使用 autovacuum 的行为
<a name="appendix.postgresql.commondbatasks.autovacuumbehavior"></a>

 在 `pg_database` 目录的 `datconnlimit` 列中引入了一个新值 `-2`，来指示在 DROP DATABASE 操作过程中已被中断的数据库为无效的。

 以下 Aurora PostgreSQL 版本中提供了这个新值：
+ 15.4 及所有更高版本
+ 14.9 及更高版本
+ 13.12 及更高版本
+ 12.16 及更高版本
+ 11.21 及更高版本

无效的数据库不会影响 autovacuum 冻结有效数据库的功能的能力。Autovacuum 会忽略无效的数据库。因此，对于 PostgreSQL 环境中的所有有效数据库，常规 vacuum 操作将继续正常且高效地运行。

**Topics**
+ [

## 监控事务 ID
](#appendix.postgresql.commondbatasks.autovacuum.monitorxid)
+ [

## 调整监控查询
](#appendix.postgresql.commondbatasks.autovacuum.monitoradjust)
+ [

## 解决无效的数据库问题
](#appendix.postgresql.commondbatasks.autovacuum.connissue)

## 监控事务 ID
<a name="appendix.postgresql.commondbatasks.autovacuum.monitorxid"></a>

 `age(datfrozenxid)` 函数常用于监控数据库的事务 ID（XID）期限，以防止事务 ID 重叠。

 由于无效数据库被排除在 autovacuum 之外，因此其事务 ID（XID）计数器可以达到最大值 `2 billion`，重叠到 `- 2 billion`，并无限期地继续此循环。监控事务 ID 重叠的典型查询可能如下所示：

```
SELECT max(age(datfrozenxid)) FROM pg_database;
```

但是，在为 `datconnlimit` 引入 -2 值后，无效的数据库可能会扭曲此查询的结果。由于这些数据库无效，而不应作为定期维护检查的一部分，因此它们可能会导致误报，致使您认为 `age(datfrozenxid)` 高于实际值。

## 调整监控查询
<a name="appendix.postgresql.commondbatasks.autovacuum.monitoradjust"></a>

 为确保准确的监控，应调整监控查询来排除无效的数据库。请遵循这一建议的查询：

```
SELECT
    max(age(datfrozenxid))
FROM
    pg_database
WHERE
    datconnlimit <> -2;
```

此查询可确保在 `age(datfrozenxid)` 计算中只考虑有效的数据库，从而真实地反映整个 PostgreSQL 环境中的事务 ID 期限。

## 解决无效的数据库问题
<a name="appendix.postgresql.commondbatasks.autovacuum.connissue"></a>

 当尝试连接到无效的数据库时，可能会遇到类似于以下内容的错误消息：

```
postgres=> \c db1
connection to server at "mydb.xxxxxxxxxx.us-west-2.rds.amazonaws.com" (xx.xx.xx.xxx), port xxxx failed: FATAL:  cannot connect to invalid database "db1"
HINT:  Use DROP DATABASE to drop invalid databases.
Previous connection kept
```

 此外，如果 `log_min_messages` 参数设置为 `DEBUG2` 或更高，您可能会注意到以下日志条目，表明 autovacuum 进程正在跳过无效的数据库：

```
       
2024-07-30 05:59:00 UTC::@:[32000]:DEBUG:  autovacuum: skipping invalid database "db6"
2024-07-30 05:59:00 UTC::@:[32000]:DEBUG:  autovacuum: skipping invalid database "db1"
```

要解决此问题，请按照尝试连接期间提供的 `HINT` 进行操作。使用 RDS 主账户或具有 `rds_superuser` 角色的数据库账户连接到任何有效的数据库，然后删除无效的数据库。

```
SELECT
    'DROP DATABASE ' || quote_ident(datname) || ';'
FROM
    pg_database
WHERE
    datconnlimit = -2 \gexec
```

# 识别并解决 Aurora PostgreSQL 中的积极真空拦截器
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring"></a>

在 PostgreSQL 中，清理对于确保数据库良好运行状况至关重要，因为它可以回收存储并防止出现[事务 ID 重叠](https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND)问题。但是，有时可能会阻止真空清理操作按预期运行，这样可能会导致性能下降、存储膨胀，甚至会因事务 ID 重叠而影响您的数据库实例的可用性。因此，识别和解决这些问题对于实现最佳数据库性能和可用性具有至关重要的意义。阅读[了解 Amazon RDS for PostgreSQL 环境中的自动真空功能](https://aws.amazon.com/blogs/database/understanding-autovacuum-in-amazon-rds-for-postgresql-environments/)，以了解有关自动真空的更多信息。

`postgres_get_av_diag()` 函数可用于识别会阻止或延迟积极 vacuum 进度的问题。提供了建议，其中可能包括用于解决可识别问题的命令，或者在无法识别问题时提供进一步诊断的指导。当龄期超过 RDS 的 5 亿个事务 ID 的[自适应自动真空](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AdaptiveAutoVacuuming)阈值时，将报告积极真空拦截器。

**事务 ID 的龄期是多少？**

事务 ID 的 `age()` 函数会计算自数据库 (`pg_database.datfrozenxid`) 或表 (`pg_class.relfrozenxid`) 的最早解冻事务 ID 以来发生的事务数。此值表示自上次积极真空操作以来的数据库活动，并突出显示即将到来的真空进程可能出现的工作负载。

**什么是积极真空？**

积极真空操作会对表中的所有页面进行全面扫描，包括在常规真空期间通常跳过的页面。这种彻底的扫描旨在“冻结”接近其最大龄期的事务 ID，从而有效地防止出现被称为[事务 ID 重叠](https://www.postgresql.org/docs/current/routine-vacuuming.html#VACUUM-FOR-WRAPAROUND)的情况。

要使 `postgres_get_av_diag()` 报告拦截器，拦截器必须至少有 5 亿个事务。

**Topics**
+ [

# 在 Aurora PostgreSQL 中安装 autovacuum 监控和诊断工具
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Installation.md)
+ [

# Aurora PostgreSQL 中的 postgres\$1get\$1av\$1diag() 函数
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Functions.md)
+ [

# 在 Aurora PostgreSQL 中解决可识别的真空拦截器
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md)
+ [

# 在 Aurora PostgreSQL 中解除无法识别的真空拦截器
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Unidentifiable_blockers.md)
+ [

# 解决 Aurora PostgreSQL 中的真空性能问题
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Performance.md)
+ [

# Aurora PostgreSQL 中的通知消息说明
](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.NOTICE.md)

# 在 Aurora PostgreSQL 中安装 autovacuum 监控和诊断工具
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Installation"></a>

`postgres_get_av_diag()` 函数目前在以下 Aurora PostgreSQL 版本中可用：
+ 17.4 及更高的 17 版本
+ 16.7 及更高的 16 版本
+ 15.11 及更高的 15 版本
+ 14.16 及更高的 14 版本
+ 13.19 及更高的 13 版本

 要使用 `postgres_get_av_diag()`，请创建 `rds_tools` 扩展。

```
postgres=> CREATE EXTENSION rds_tools ;
CREATE EXTENSION
```

验证是否已安装扩展。

```
postgres=> \dx rds_tools
             List of installed extensions
   Name    | Version |  Schema   |                    Description
 ----------+---------+-----------+----------------------------------------------------------
 rds_tools |   1.9   | rds_tools | miscellaneous administrative functions for RDS PostgreSQL
 1 row
```

验证是否已创建函数。

```
postgres=> SELECT
    proname function_name,
    pronamespace::regnamespace function_schema,
    proowner::regrole function_owner
FROM
    pg_proc
WHERE
    proname = 'postgres_get_av_diag';
    function_name     | function_schema | function_owner
----------------------+-----------------+----------------
 postgres_get_av_diag | rds_tools       | rds_superuser
(1 row)
```

# Aurora PostgreSQL 中的 postgres\$1get\$1av\$1diag() 函数
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Functions"></a>

`postgres_get_av_diag()` 函数会检索有关 Aurora PostgreSQL 数据库中阻止或滞后的 autovacuum 进程的诊断信息。为了获得准确的结果，需要在具有最早事务 ID 的数据库中执行查询。有关使用具有最早事务 ID 的数据库的更多信息，请参阅[未连接到具有最早事务 ID 龄期的数据库](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.NOTICE.md)

```
SELECT
    blocker,
    DATABASE,
    blocker_identifier,
    wait_event,
    TO_CHAR(autovacuum_lagging_by, 'FM9,999,999,999') AS autovacuum_lagging_by,
    suggestion,
    suggested_action
FROM (
    SELECT
        *
    FROM
        rds_tools.postgres_get_av_diag ()
    ORDER BY
        autovacuum_lagging_by DESC) q;
```

`postgres_get_av_diag()` 函数将返回一个包含以下信息的表：

**blocker**  
指定阻止真空的数据库活动的类别。  
+ [活动语句](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Active_statement)
+ [事务中空闲](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Idle_in_transaction)
+ [准备好的事务](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Prepared_transaction)
+ [逻辑复制槽](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Logical_replication_slot)
+ [读取器实例](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Reader_instances)
+ [临时表](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Temporary_tables)

**database**  
在适用和支持的情况下指定数据库的名称。这是其中活动正在进行并正在阻止或将阻止自动真空的数据库。这是您需要连接并执行操作的数据库。

**blocker\$1identifier**  
指定正在阻止或将阻止自动真空的活动的标识符。该标识符可以是进程 ID 以及 SQL 语句、准备好的事务、只读副本的 IP 地址以及复制槽的名称（逻辑或物理）。

**wait\$1event**  
指定阻止会话的[等待事件](AuroraPostgreSQL.Tuning.md)，适用于以下拦截器：  
+ 活动语句
+ 事务中空闲

**autovacum\$1lagging\$1by**  
指定自动真空在每个类别的积压工作中滞后的事务数。

**suggestion**  
指定解除拦截器的建议。这些说明包括活动所在的数据库的名称（如果适用）、会话的进程 ID（PID）（如果适用）以及要执行的操作。

**suggested\$1action**  
建议需要执行哪些操作来解除拦截器。

# 在 Aurora PostgreSQL 中解决可识别的真空拦截器
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Identifiableblockers"></a>

自动真空会执行积极真空操作，并将事务 ID 的龄期降低到低于由 RDS 实例的 `autovacuum_freeze_max_age` 参数指定的阈值。您可以使用 Amazon CloudWatch 指标 `MaximumUsedTransactionIDs` 跟踪此龄期。

要查找 Amazon RDS 实例的 `autovacuum_freeze_max_age` 设置（默认为 2 亿个事务 ID），您可以使用以下查询：

```
SELECT
    TO_CHAR(setting::bigint, 'FM9,999,999,999') autovacuum_freeze_max_age
FROM
    pg_settings
WHERE
    name = 'autovacuum_freeze_max_age';
```

请注意，`postgres_get_av_diag()` 仅在龄期超过 Amazon RDS 的 5 亿个事务 ID 的[自适应自动真空](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum.AdaptiveAutoVacuuming)阈值时检查积极真空拦截器。要使 `postgres_get_av_diag()` 检测拦截器，拦截器必须至少有 5 亿个事务。

`postgres_get_av_diag()` 函数可识别以下类型的拦截器：

**Topics**
+ [

## 活动语句
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Active_statement)
+ [

## 事务中空闲
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Idle_in_transaction)
+ [

## 准备好的事务
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Prepared_transaction)
+ [

## 逻辑复制槽
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Logical_replication_slot)
+ [

## 读取器实例
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Reader_instances)
+ [

## 临时表
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Temporary_tables)

## 活动语句
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Active_statement"></a>

在 PostgreSQL 中，活动语句是数据库当前正在执行的 SQL 语句。这包括查询、事务或任何正在进行的操作。通过 `pg_stat_activity` 进行监控时，状态列指示具有相应 PID 的进程处于活动状态。

`postgres_get_av_diag()` 函数在识别系活动语句的语句时会显示类似于以下内容的输出。

```
blocker               | Active statement
database              | my_database
blocker_identifier    | SELECT pg_sleep(20000);
wait_event            | Timeout:PgSleep
autovacuum_lagging_by | 568,600,871
suggestion            | Connect to database "my_database", review carefully and you may consider terminating the process using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide.
suggested_action      | {"SELECT pg_terminate_backend (29621);"}
```

**建议采取的措施**

按照 `suggestion` 列中的指导，用户可以连接到存在活动语句的数据库，并按照 `suggested_action` 列中的指定，建议仔细查看终止会话的选项。如果终止是安全的，则可以使用 `pg_terminate_backend()` 函数终止会话。此操作可由管理员（如 RDS 主账户）或具有所需 `pg_terminate_backend()` 权限的用户执行。

**警告**  
已终止的会话将撤消 (`ROLLBACK`) 其所做的更改。根据您的要求，您可能需要重新运行相应语句。但是，建议只有在自动真空过程完成其积极真空操作之后才这样做。

## 事务中空闲
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Idle_in_transaction"></a>

事务中空闲语句是指已打开显式事务（例如通过发出 `BEGIN` 语句）、执行了一些工作，并且现在正在等待客户端传递更多工作或通过发出 `COMMIT`、`ROLLBACK` 或 `END`（这将导致隐式 `COMMIT`）来发出事务结束信号的任何会话。

`postgres_get_av_diag()` 函数在将 `idle in transaction` 语句识别为拦截器时，显示类似于以下内容的输出。

```
blocker               | idle in transaction
database              | my_database
blocker_identifier    | INSERT INTO tt SELECT * FROM tt;
wait_event            | Client:ClientRead
autovacuum_lagging_by | 1,237,201,759
suggestion            | Connect to database "my_database", review carefully and you may consider terminating the process using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide.
suggested_action      | {"SELECT pg_terminate_backend (28438);"}
```

**建议采取的措施**

如 `suggestion` 列中所示，您可以连接到存在事务中空闲会话的数据库，并使用 `pg_terminate_backend()` 函数终止会话。该用户可以是您的管理员（RDS 主账户）用户或具有 `pg_terminate_backend()` 权限的用户。

**警告**  
已终止的会话将撤消 (`ROLLBACK`) 其所做的更改。根据您的要求，您可能需要重新运行相应语句。但是，建议只有在自动真空过程完成其积极真空操作之后才这样做。

## 准备好的事务
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Prepared_transaction"></a>

PostgreSQL 允许属于称为[准备好的事务](https://www.postgresql.org/docs/current/sql-prepare-transaction.html)的两阶段提交策略一部分的事务。通过将 `max_prepared_transactions` 参数设置为非零值即可启用这些功能。准备好的事务旨在确保事务的持久性，即使在数据库崩溃、重启或客户端断开连接后仍可用。与定期事务一样，它们会被分配一个事务 ID，并且可能会影响自动真空。如果保持已准备状态，则自动真空将无法执行冻结，这样可能会导致事务 ID 重叠。

当事务被无限期地准备而没有被事务管理器解决时，它们将成为孤立的已准备事务。解决此问题的唯一方法是分别使用 `COMMIT PREPARED` 或 `ROLLBACK PREPARED` 命令提交或回滚事务。

**注意**  
请注意，在准备事务期间进行的备份在还原后仍将包含该事务。有关如何查找和关闭此类事务的信息，请参阅以下信息。

`postgres_get_av_diag()` 函数在识别出系已准备事务的拦截器时显示以下输出。

```
blocker               | Prepared transaction
database              | my_database
blocker_identifier    | myptx
wait_event            | Not applicable
autovacuum_lagging_by | 1,805,802,632
suggestion            | Connect to database "my_database" and consider either COMMIT or ROLLBACK the prepared transaction using suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide.
suggested_action      | {"COMMIT PREPARED 'myptx';",[OR],"ROLLBACK PREPARED 'myptx';"}
```

**建议采取的措施**

如建议列中所述，连接到已准备事务所在的数据库。根据 `suggested_action` 列，仔细查看是执行 `COMMIT` 还是 `ROLLBACK`，并执行适当的操作。

为了总体上监控已准备事务，PostgreSQL 提供了一个名为 `pg_prepared_xacts` 的目录视图。您可以使用以下查询来查找已准备事务。

```
SELECT
    gid,
    prepared,
    owner,
    database,
    transaction AS oldest_xmin
FROM
    pg_prepared_xacts
ORDER BY
    age(transaction) DESC;
```

## 逻辑复制槽
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Logical_replication_slot"></a>

复制槽的用途是保存未使用的更改，直到它们被复制到目标服务器。有关更多信息，请参阅 PostgreSQL 的 [Logical replication](https://www.postgresql.org/docs/current/logical-replication.html)。

有两种类型的逻辑复制槽。

**非活动逻辑复制槽**

复制终止后，无法删除未使用的事务日志，且复制槽变为非活动状态。尽管订阅用户当前未使用非活动逻辑复制槽，但它仍保留在服务器上，从而保留 WAL 文件并防止删除旧的事务日志。这样会增加磁盘使用量，特别是阻止自动真空清理内部目录表，因为系统必须保护 LSN 信息不被覆盖。如果不加以解决，可能会导致目录臃肿、性能下降和重叠真空风险增加，从而可能导致事务停机。

**活动但速度较慢的逻辑复制槽**

有时，由于逻辑复制的性能下降，目录中无效元组的删除会延迟。这种复制延迟会减慢 `catalog_xmin` 的更新速度，并可能导致目录臃肿和重叠真空。

`postgres_get_av_diag()` 函数在找到逻辑复制槽作为拦截器时，会显示类似于以下内容的输出。

```
blocker               | Logical replication slot
database              | my_database
blocker_identifier    | slot1
wait_event            | Not applicable
autovacuum_lagging_by | 1,940,103,068
suggestion            | Ensure replication is active and resolve any lag for the slot if active. If inactive, consider dropping it using the command in suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide.
suggested_action      | {"SELECT pg_drop_replication_slot('slot1') FROM pg_replication_slots WHERE active = 'f';"}
```

**建议采取的措施**

要解决此问题，请检查复制配置中是否存在可能终止应用进程的目标架构或数据问题。最常见的原因如下：
+ 缺少列
+ 数据类型不兼容
+ 数据不匹配
+ 缺少表

如果该问题与基础设施问题有关：
+ 网络问题 – [如何解决 Amazon RDS 数据库处于不兼容网络状态的问题？](https://repost.aws/knowledge-center/rds-incompatible-network)。
+ 数据库或数据库实例不可用的原因如下：
  + 副本实例用尽存储空间 – 有关添加存储的信息，请查看 [Amazon RDS DB 实例存储空间不足](https://repost.aws/knowledge-center/rds-out-of-storage)。
  + 不兼容参数 – 有关如何能够解决该问题的更多信息，请查看[如何修复一直处于不兼容参数状态的 Amazon RDS 数据库实例问题？](https://repost.aws/knowledge-center/rds-incompatible-parameters)。

如果您的实例位于 AWS 网络之外或 AWS EC2 上，请咨询您的管理员，了解如何解决可用性或基础设施相关问题。

**删除非活动槽**

**警告**  
注意：在删除复制槽之前，请仔细确保其没有正在进行的复制、处于非活动状态且处于不可恢复状态。过早删除槽可能会中断复制或导致数据丢失。

确认不再需要复制槽后，将其删除以允许自动真空继续运行。条件 `active = 'f'` 可确保仅删除非活动槽。

```
SELECT pg_drop_replication_slot('slot1') WHERE active ='f'
```

## 读取器实例
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Reader_instances"></a>

在启用 hot\$1standby\$1feedback 设置之后，对于读取器实例上正在运行的查询仍然需要的死行，该设置会阻止写入器实例上的 autovacuum 删除这些死行。此行为是必需的，因为在读取器实例（同样适用于 Aurora Global Database 中的读取器实例）上运行的查询要求这些行在写入器实例上保持可用，从而防止出现查询冲突和查询取消。

**注意**  
`hot_standby_feedback` 在 Aurora PostgreSQL 中默认启用且不可修改。

`postgres_get_av_diag()` 函数在找到以物理复制槽作为拦截器的只读副本时，会显示类似于以下内容的输出。

```
blocker               | Oldest query running on aurora reader
database              | Not applicable
blocker_identifier    | my-aurora-reader-2
wait_event            | Not applicable
autovacuum_lagging_by | 540,122,859
suggestion            | Run the following query on the reader "my-aurora-reader-2" to find the long running query:                                                                                                 
                      | SELECT * FROM pg_catalog.pg_stat_activity WHERE backend_xmin::text::bigint = 523476310;                                                                                                    
                      | Review carefully and you may consider terminating the query on reader using suggested_action.                                                      
suggested_action      | {"SELECT pg_terminate_backend(pid) FROM pg_catalog.pg_stat_activity WHERE backend_xmin::text::bigint = 523476310;","                                                                       
                      | [OR]                                                                                                                                                                                    
                      | ","Delete the reader if not needed"}
```

按照 `suggested_action` 列中的建议，仔细查看用于解除阻止自动真空的这些选项。
+ **终止查询** – 按照建议列中的指导，您可以连接到只读副本，如 suggested\$1action 列中指定，建议仔细查看终止会话的选项。如果终止被视为是安全的，则可以使用 `pg_terminate_backend()` 函数终止会话。此操作可由管理员（如 RDS 主账户）或具有所需 pg\$1terminate\$1backend() 权限的用户执行。

  您可以在只读副本上运行以下 SQL 命令来终止用于阻止主数据库上的真空清理旧行的查询。在函数的输出中报告 `backend_xmin` 的值：

  ```
  SELECT
      pg_terminate_backend(pid)
  FROM
      pg_catalog.pg_stat_activity
  WHERE
      backend_xmin::text::bigint = backend_xmin;
  ```
+ **如果不需要读取器实例，请将其删除** – 如果不再需要读取器实例，则可以将其删除。这将消除相关的复制开销，并允许主数据库在不受实例阻碍的情况下回收事务日志。

## 临时表
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Temporary_tables"></a>

使用 `TEMPORARY` 关键字创建的[临时表](https://www.postgresql.org/docs/current/sql-createtable.html)驻留在临时架构中，例如 pg\$1temp\$1xxx，并且只能由创建它们的会话访问。会话结束时会删除临时表。但是，这些表对于 PostgreSQL 的自动真空流程是不可见的，必须由创建它们的会话手动清理。尝试从另一个会话中清空临时表是无效的。

在特殊情况下，存在一个临时表，但没有活动会话拥有该表。如果所属会话由于致命崩溃、网络问题或类似事件而意外结束，则可能无法清理临时表，从而会将其留作为“孤立”表。当 PostgreSQL 自动真空进程检测到孤立的临时表时，它会记录以下消息：

```
LOG: autovacuum: found orphan temp table \"%s\".\"%s\" in database \"%s\"
```

`postgres_get_av_diag()` 函数在将临时表识别为拦截器时，会显示类似于以下内容的输出。要使该函数正确显示与临时表相关的输出，需要在存在这些表的同一数据库中执行该函数。

```
blocker               | Temporary table
database              | my_database
blocker_identifier    | pg_temp_14.ttemp
wait_event            | Not applicable
autovacuum_lagging_by | 1,805,802,632
suggestion            | Connect to database "my_database". Review carefully, you may consider dropping temporary table using command in suggested_action. For more information, see Working with PostgreSQL autovacuum in the Amazon RDS User Guide.
suggested_action      | {"DROP TABLE ttemp;"}
```

**建议采取的措施**

按照输出的 `suggestion` 列中提供的说明识别并删除阻止自动真空运行的临时表。使用以下命令删除由 `postgres_get_av_diag()` 报告的临时表。根据 `postgres_get_av_diag()` 函数提供的输出替换表名称。

```
DROP TABLE my_temp_schema.my_temp_table;
```

以下查询可用于识别临时表：

```
SELECT
    oid,
    relname,
    relnamespace::regnamespace,
    age(relfrozenxid)
FROM
    pg_class
WHERE
relpersistence = 't'
ORDER BY
    age(relfrozenxid) DESC;
```

# 在 Aurora PostgreSQL 中解除无法识别的真空拦截器
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Unidentifiable_blockers"></a>

本节探讨了可能阻碍清理取得进展的其他原因。`postgres_get_av_diag()` 函数目前无法直接识别这些问题。

**Topics**
+ [

## 索引不一致
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Index_inconsistency)
+ [

## 事务速率异常高
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.High_transaction_rate)

## 索引不一致
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Index_inconsistency"></a>

逻辑上不一致的索引可能会阻碍自动真空取得进展。在索引的真空阶段或 SQL 语句访问索引时，将记录以下错误或类似错误。

```
ERROR: right sibling's left-link doesn't match:block 5 links to 10 instead of expected 2 in index ix_name
```

```
ERROR: failed to re-find parent key in index "XXXXXXXXXX" for deletion target page XXX
CONTEXT:  while vacuuming index index_name of relation schema.table
```

**指南**

在手动 `VACUUM FREEZE` 上使用 `INDEX_CLEANUP` 重建索引或跳过索引。
+ **使用 CONCURRENTLY 选项** – 在 PostgreSQL 版本 12 之前，重建索引需要独占的表锁定，从而限制对表的访问。在 PostgreSQL 版本 12 及更高版本中，CONCURRENTLY 选项允许行级别锁定，从而显著提高表的可用性。命令如下：

  ```
  REINDEX INDEX ix_name CONCURRENTLY;
  ```

  虽然 CONCURRENTLY 的破坏性较小，但在繁忙的表中其速度可能会变慢。如果可能，可以考虑在流量较低的时段构建索引。有关更多信息，请参阅 *PostgreSQL* 文档中的 [REINDEX](https://www.postgresql.org/docs/current/sql-reindex.html)。
+ **使用 INDEX\$1CLEANUP FALSE 选项** – 如果索引很大并且估计需要大量时间才能完成，则您可以通过在排除索引的同时执行手动 VACUUM FREEZE 来解除阻止 autovacuum。PostgreSQL 版本 12 及更高版本中提供了此功能。

  绕过索引将允许您跳过索引不一致的真空过程并缓解重叠问题。但是，这样并不能解决潜在的无效页面问题。要完全应对和解决无效页面问题，您仍然需要重建索引。

## 事务速率异常高
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.High_transaction_rate"></a>

在 PostgreSQL 中，事务速率高会显著影响自动真空的性能，从而导致无效元组的清理速度变慢，并增加事务 ID 重叠的风险。您可以通过衡量两个时间段之间的 `max(age(datfrozenxid))` 差异（通常为每秒）来监控事务速率。此外，您还可以使用 RDS 性能详情中的以下计数器指标来衡量事务速率（xact\$1commit 与 xact\$1rollback 之和），即事务总数。


|  计数器  |  类型  |  单位  |  指标  | 
| --- | --- | --- | --- | 
|  xact\$1commit  |  事务  |  每秒提交数  |  db.Transactions.xact\$1commit  | 
|  xact\$1rollback  |  事务  |  每秒回滚数  |  db.Transactions.xact\$1rollback  | 

快速增加表示高事务负载，这可能会使自动真空不堪重负，从而导致膨胀、锁争用和潜在的性能问题。这样可能会以多种方式对自动真空进程产生负面影响：
+ **表活动：**正在经历清理操作的特定表可能会遇到大量事务，从而导致延迟。
+ **系统资源：**整个系统可能会过载，使自动真空难以访问必要的资源以便高效运行。

请考虑以下策略，以允许自动真空更有效地运行并跟上其任务：

1. 如果可能，请降低事务速率。请考虑在可行的情况下对类似的事务进行批处理或分组。

1. 在非高峰时段，每晚、每周或每两周通过手动 `VACUUM FREEZE` 操作来定位频繁更新的表。

1. 请考虑扩展您的实例类以分配更多系统资源来处理高事务量和自动真空操作。

# 解决 Aurora PostgreSQL 中的真空性能问题
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Performance"></a>

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

**Topics**
+ [

## 清理大型索引
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Large_indexes)
+ [

## 需要清理的表或数据库太多
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Multiple_tables)
+ [

## 正在运行积极真空（以防止重叠）
](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Aggressive_vacuum)

## 清理大型索引
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Large_indexes"></a>

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 操作何时因内存不足而运行缓慢。有关此函数的更多信息，请参阅[在 Aurora PostgreSQL 中安装 autovacuum 监控和诊断工具](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Installation.md)。

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

**`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 Aurora User Guide](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Autovacuum.html).
```

**注意**  
`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](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Autovacuum.html).
```

**指南**

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

**增加用于清理的内存**

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

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

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

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

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

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

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

**禁用 INDEX\$1CLEANUP**

PostgreSQL 版本 12 及更高版本中的手动 `VACUUM` 允许跳过索引清理阶段，而 PostgreSQL 版本 14 及更高版本中的紧急自动真空会根据 [https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-VACUUM-FAILSAFE-AGE](https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-VACUUM-FAILSAFE-AGE) 参数自动执行此操作。

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

有关处理大型索引的更多指导，请参阅[使用大型索引管理 autovacuum](Appendix.PostgreSQL.CommonDBATasks.Autovacuum.LargeIndexes.md)中的文档。

**并行索引清理**

从 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](https://aws.amazon.com/blogs/database/parallel-vacuuming-in-amazon-rds-for-postgresql-and-amazon-aurora-postgresql/)。

## 需要清理的表或数据库太多
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Multiple_tables"></a>

如 PostgreSQL 的[自动真空进程守护程序](https://www.postgresql.org/docs/current/routine-vacuuming.html#AUTOVACUUM')文档中所述，自动真空进程守护程序通过多个进程运行。这包括一个持久性自动真空启动程序，负责为系统中的每个数据库启动自动真空工件进程。该启动程序安排这些工件大约每个数据库每 `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\$1max\$1workers**

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

## 正在运行积极真空（以防止重叠）
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Aggressive_vacuum"></a>

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

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

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

有关积极真空的更多信息，请参阅[当积极真空已经在运行时](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.NOTICE.md)。

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

```
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` 指定）。

# Aurora PostgreSQL 中的通知消息说明
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.NOTICE"></a>

 `postgres_get_av_diag()` 函数提供以下通知消息：

**当龄期尚未达到监控阈值时**  
默认情况下，`postgres_get_av_diag()` 识别拦截器的监控阈值为 5 亿个事务。如果 `postgres_get_av_diag()` 生成以下通知，则表示事务龄期尚未达到此阈值。  

```
NOTICE: postgres_get_av_diag() checks for blockers that prevent aggressive vacuums only, it does so only after exceeding dvb_threshold which is 500,000,000 and age of this PostgreSQL cluster is currently at 2.
```

**未连接到具有最早事务 ID 龄期的数据库**  
当连接到具有最早事务 ID 龄期的数据库时，`postgres_get_av_diag()` 函数可提供最准确的输出。`postgres_get_av_diag()` 报告的具有最早事务 ID 龄期的数据库将不同于您的案例中的“my\$1database”。如果您未连接到正确的数据库，则会生成以下通知：  

```
NOTICE: You are not connected to the database with the age of oldest transaction ID. Connect to my_database database and run postgres_get_av_diag() for accurate reporting.
```
出于以下原因，连接到具有最早事务龄期的数据库非常重要：  
+ **识别临时表拦截器：**由于临时表的元数据特定于每个数据库，因此它们通常位于在其中创建临时表的数据库中。但是，如果临时表恰好是最重要的拦截器，并且位于具有最早事务的数据库中，则可能会产生误导。连接到正确的数据库可确保准确识别临时表拦截器。
+ **诊断缓慢真空：**索引元数据和表计数信息是特定于数据库的，是诊断缓慢真空问题所必需的。

**按龄期计算具有最早事务的数据库位于 rdsadmin 或 template0 数据库中**  
在某些情况下，`rdsadmin` 或 `template0` 数据库可能会被标识为具有最早事务 ID 龄期的数据库。如果发生这种情况，`postgres_get_av_diag()` 将发出以下通知：  

```
NOTICE: The database with the age of oldest transaction ID is rdsadmin or template0, reach out to support if the reported blocker is in rdsadmin or template0.
```
验证列出的拦截器是否不是来自这两个数据库中的任何一个。如果据报告 `rdsadmin` 或 `template0` 中存在拦截器，请联系支持部门，因为这些数据库对用户不可访问，需要干预。  
`rdsadmin` 或 `template0` 数据库包含最重要拦截器的可能性极小。

**当积极真空已经在运行时**  
`postgres_get_av_diag()` 函数旨在报告何时正在运行积极真空进程，但它仅在真空处于活动状态至少 1 分钟后触发此输出。这种有意的延迟有助于减少误报的可能性。通过等待，该函数可确保仅报告有效、重要的真空，从而可更准确、更可靠地监控真空活动。  
`postgres_get_av_diag()` 函数在检测到一个或多个正在进行的积极真空时会生成以下通知。  

```
NOTICE: Your database is currently running aggressive vacuum to prevent wraparound, monitor autovacuum performance.
```
如通知中所述，请继续监控真空的性能。有关积极真空的更多信息，请参阅[正在运行积极真空（以防止重叠）](Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Resolving_Performance.md#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Aggressive_vacuum)

**当自动真空关闭时**  
如果数据库实例上禁用了自动真空，则 `postgres_get_av_diag()` 函数会生成以下通知：  

```
NOTICE: Autovacuum is OFF, we strongly recommend to enable it, no restart is necessary.
```
Autovacuum 是 Aurora PostgreSQL 数据库实例的一项关键功能，可确保数据库顺畅运行。它会自动删除旧的行版本，回收存储空间，并防止表膨胀，从而帮助保持表和索引的高效性，以实现最佳性能。此外，它还可以防止发生事务 ID 重叠，这可能会停止 Amazon RDS 实例上的事务。禁用自动真空会导致数据库性能和稳定性的长期下降。建议您始终将其保持开启状态。有关更多信息，请参阅 [Understanding autovacuum in Aurora PostgreSQL environments](https://aws.amazon.com/blogs/database/understanding-autovacuum-in-amazon-rds-for-postgresql-environments/)。  
关闭自动真空并不会阻止积极真空。一旦您的表达到 `autovacuum_freeze_max_age` 阈值，仍会发生这种情况。

**剩余的事务数严重不足**  
`postgres_get_av_diag()` 函数会在即将发生重叠真空时生成以下通知。当您的 Amazon RDS 实例距离可能拒绝新事务还有 1 亿个事务时，将发出此通知。  

```
WARNING: Number of transactions remaining is critically low, resolve issues with autovacuum or perform manual VACUUM FREEZE before your instance stops accepting transactions.
```
需要立即采取行动以免发生数据库停机。您应该密切监控真空操作，并考虑在受影响的数据库上手动启动 `VACUUM FREEZE` 以防止事务失败。