

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

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

**Topics**
+ [页面无效](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Invalid_pages)
+ [索引不一致](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Index_inconsistency)
+ [事务速率异常高](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.High_transaction_rate)

## 页面无效
<a name="Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Invalid_pages"></a>

当 PostgreSQL 在访问页面时检测到该页面的校验和不匹配时，就会出现无效页面错误。内容无法读取，从而阻止自动真空冻结元组。这样实际上会停止清理过程。PostgreSQL 的日志中写入了以下错误：

```
WARNING:  page verification failed, calculated checksum YYYYY but expected XXXX
ERROR:  invalid page in block ZZZZZ of relation base/XXXXX/XXXXX
CONTEXT:  automatic vacuum of table myschema.mytable
```

**确定对象类型**

```
ERROR: invalid page in block 4305910 of relation base/16403/186752608 
WARNING: page verification failed, calculated checksum 50065 but expected 60033
```

从错误消息中，路径 `base/16403/186752608` 提供以下信息：
+ “base”是 PostgreSQL 数据目录下的目录名称。
+ “16403”是数据库 OID，您可以在 `pg_database` 系统目录中进行查找。
+ “186752608”是 `relfilenode`，您可以使用它在 `pg_class` 系统目录中查找架构和对象名称。

通过在受影响的数据库中检查以下查询的输出，可以确定对象类型。以下查询会检索 oid 为 186752608 的对象信息。将该 OID 替换为与您遇到的错误相关的 OID。

```
SELECT
    relname AS object_name,
    relkind AS object_type,
    nspname AS schema_name
FROM
    pg_class c
    JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE
    c.oid = 186752608;
```

有关更多信息，请参阅 PostgreSQL 文档 [https://www.postgresql.org/docs/current/catalog-pg-class.html](https://www.postgresql.org/docs/current/catalog-pg-class.html)，以了解所有支持的对象类型，如 `pg_class` 中的 `relkind` 列所示。

**指南**

此问题的最有效解决方案取决于特定 Amazon RDS 实例的配置以及受不一致页面影响的数据类型。

**如果对象类型是索引：**

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

  ```
  REINDEX INDEX ix_name CONCURRENTLY;
  ```

  虽然 `CONCURRENTLY` 的破坏性较小，但在繁忙的表中其速度可能会变慢。如果可能，可以考虑在流量较低的时段构建索引。

  有关更多信息，请参阅 PostgreSQL [REINDEX](https://www.postgresql.org/docs/current/sql-reindex.html) 文档。
+ **使用 `INDEX_CLEANUP FALSE` 选项** – 如果索引很大并且估计需要大量时间才能完成，则您可以通过在排除索引的同时执行手动 `VACUUM FREEZE` 来解除阻止 autovacuum。PostgreSQL 版本 12 及更高版本中提供了此功能。

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

**如果对象类型为实体化视图：**

如果实体化视图上出现无效页面错误，请登录到受影响的数据库并刷新以解决无效的页面：

刷新实体化视图：

```
REFRESH MATERIALIZED VIEW schema_name.materialized_view_name;
```

如果刷新失败，请尝试重新创建：

```
DROP MATERIALIZED VIEW schema_name.materialized_view_name;
CREATE MATERIALIZED VIEW schema_name.materialized_view_name AS query;
```

刷新或重新创建实体化视图可在不影响基础表数据的情况下还原该视图。

**对于所有其他对象类型：**

对于所有其他对象类型，请联系 AWS 支持。

## 索引不一致
<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` 重建索引或跳过索引。有关如何重建索引的信息，请参阅[如果对象类型是索引](#Appendix.PostgreSQL.CommonDBATasks.Autovacuum_Monitoring.Invalid_pages)。
+ **使用 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. 请考虑扩展您的实例类以分配更多系统资源来处理高事务量和自动真空操作。