

# 管理 Aurora PostgreSQL 的查询执行计划
<a name="AuroraPostgreSQL.Optimize"></a>

Aurora PostgreSQL 查询计划管理是一项可选功能，可与 Amazon Aurora PostgreSQL 兼容版数据库集群结合使用。此功能打包为 `apg_plan_mgmt` 扩展，您可以将其安装在 Aurora PostgreSQL 数据库集群中。查询计划管理可让您管理优化器为 SQL 应用程序生成的查询执行计划。`apg_plan_mgmt` AWS 扩展基于 PostgreSQL 数据库引擎的原生查询处理功能而构建。

接下来，您可以找到有关 Aurora PostgreSQL 查询计划管理功能、如何设置此功能以及如何将其与 Aurora PostgreSQL 数据库集群结合使用的信息。在开始之前，我们建议您查看适用于您的 Aurora PostgreSQL 版本的特定 `apg_plan_mgmt` 扩展版本的所有版本注释。有关更多信息，请参阅《Aurora PostgreSQL 版本注释》**中的 [Aurora PostgreSQL apg\$1plan\$1mgmt 扩展版本](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraPostgreSQLReleaseNotes/AuroraPostgreSQL.Extensions.html#AuroraPostgreSQL.Extensions.apg_plan_mgmt)。

**Topics**
+ [Aurora PostgreSQL 查询计划管理概览](AuroraPostgreSQL.Optimize.overview.md)
+ [Aurora PostgreSQL 查询计划管理的最佳实践](AuroraPostgreSQL.Optimize.BestPractice.md)
+ [Aurora PostgreSQL 查询计划管理](AuroraPostgreSQL.Optimize.Start.md)
+ [捕获 Aurora PostgreSQL 执行计划](AuroraPostgreSQL.Optimize.CapturePlans.md)
+ [使用 Aurora PostgreSQL 托管式计划](AuroraPostgreSQL.Optimize.UsePlans.md)
+ [在 dba\$1plans 视图中检查 Aurora PostgreSQL 查询计划](AuroraPostgreSQL.Optimize.ViewPlans.md)
+ [改进 Aurora PostgreSQL 查询计划](AuroraPostgreSQL.Optimize.Maintenance.md)
+ [删除 Aurora PostgreSQL 查询计划](AuroraPostgreSQL.Optimize.Deleting.md)
+ [导出和导入 Aurora PostgreSQL 的托管式计划](AuroraPostgreSQL.Optimize.Maintenance.ExportingImporting.md)
+ [Aurora PostgreSQL 查询计划管理的参数参考](AuroraPostgreSQL.Optimize.Parameters.md)
+ [Aurora PostgreSQL 查询计划管理的函数参考](AuroraPostgreSQL.Optimize.Functions.md)
+ [Aurora PostgreSQL 兼容版的 apg\$1plan\$1mgmt.dba\$1plans 视图参考](AuroraPostgreSQL.Optimize.dba_plans_view_Reference.md)
+ [查询计划管理高级功能](AuroraPostgreSQL.QPM.Advanced.md)

# Aurora PostgreSQL 查询计划管理概览
<a name="AuroraPostgreSQL.Optimize.overview"></a>

Aurora PostgreSQL 查询计划管理旨在确保计划的稳定性，而无论对数据库的更改是否可能导致查询计划回归。当优化程序在系统或数据库更改后为给定的 SQL 语句选择次优计划时，就会发生*查询计划回归*。更改统计数据、约束、环境设置、查询参数绑定以及升级 PostgreSQL 数据库引擎都可能导致计划回归。

使用 Aurora PostgreSQL 查询计划管理，您可以控制更改查询执行计划的方式和时间。Aurora PostgreSQL 查询计划管理的优势包括以下几点。
+ 通过强制优化程序从少量的已知良好计划中选择，提高计划的稳定性。
+ 集中优化计划，然后在全局范围内分发最佳计划。
+ 确定未使用的索引，并评估创建或删除索引的影响。
+ 自动检测优化程序发现的最低成本的新计划。
+ 尝试使用风险较小的新优化程序功能，因为您可以选择仅批准将提高性能的计划更改。

您可以主动使用查询计划管理提供的工具，为某些查询指定最佳计划。或者，您可以使用查询计划管理来应对不断变化的情况，并避免计划回归。有关更多信息，请参阅 [Aurora PostgreSQL 查询计划管理的最佳实践](AuroraPostgreSQL.Optimize.BestPractice.md)。

**Topics**
+ [支持的 SQL 语句](#AuroraPostgreSQL.Optimize.overview.features)
+ [查询计划管理限制](#AuroraPostgreSQL.Optimize.overview.limitations)
+ [查询计划管理术语](#AuroraPostgreSQL.Optimize.Start-terminology)
+ [Aurora PostgreSQL 查询计划管理版本](#AuroraPostgreSQL.Optimize.overview.versions)
+ [开启 Aurora PostgreSQL 查询计划管理](#AuroraPostgreSQL.Optimize.Enable)
+ [升级 Aurora PostgreSQL 查询计划管理](#AuroraPostgreSQL.Optimize.Upgrade)
+ [关闭 Aurora PostgreSQL 查询计划管理](#AuroraPostgreSQL.Optimize.Enable.turnoff)

## 支持的 SQL 语句
<a name="AuroraPostgreSQL.Optimize.overview.features"></a>

查询计划管理支持以下类型的 SQL 语句。
+ 任何 SELECT、INSERT、UPDATE 或 DELETE 语句，而不考虑复杂性。
+ 已准备好语句。有关更多信息，请参阅 PostgreSQL 文档中的 [PREPARE](https://www.postgresql.org/docs/14/sql-prepare.html)。
+ 动态语句，包括那些在即时模式下运行的语句。有关更多信息，请参阅 PostgreSQL 文档中的[动态 SQL](https://www.postgresql.org/docs/current/ecpg-dynamic.html) 和 [EXECUTE IMMEDIATE](https://www.postgresql.org/docs/current/ecpg-sql-execute-immediate.html)。
+ 嵌入式 SQL 命令和语句。有关更多信息，请参阅 PostgreSQL 文档中的[嵌入式 SQL 命令](https://www.postgresql.org/docs/current/ecpg-sql-commands.html)。
+ 命名函数内的语句。有关更多信息，请参阅 PostgreSQL 文档中的 [CREATE FUNCTION](https://www.postgresql.org/docs/current/sql-createfunction.html)。
+ 包含临时表的语句。
+ 过程和 DO 块内的语句。

您可以在手动模式下将查询计划管理与 `EXPLAIN` 结合使用来捕获计划，而无需实际运行它。有关更多信息，请参阅 [分析优化程序的已选择计划](AuroraPostgreSQL.Optimize.UsePlans.md#AuroraPostgreSQL.Optimize.UsePlans.AnalyzePlans)。要了解有关查询计划管理的模式（手动、自动）的更多信息，请参阅 [捕获 Aurora PostgreSQL 执行计划](AuroraPostgreSQL.Optimize.CapturePlans.md)。

Aurora PostgreSQL 查询计划管理支持所有 PostgreSQL 语言功能，包括分区表、继承、行级安全性和递归公用表表达式（CTE）。要了解有关这些 PostgreSQL 语言功能的更多信息，请参阅 PostgreSQL 文档中的[表分区](https://www.postgresql.org/docs/current/ddl-partitioning.html)、[行安全策略](https://www.postgresql.org/docs/current/ddl-rowsecurity.html)和 [WITH 查询（公用表表达式）](https://www.postgresql.org/docs/current/queries-with.html)以及其他主题。

有关 Aurora PostgreSQL 查询计划管理功能的不同版本的信息，请参阅《Aurora PostgreSQL 版本注释》**中的 [Aurora PostgreSQL apg\$1plan\$1mgmt 扩展版本](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraPostgreSQLReleaseNotes/AuroraPostgreSQL.Extensions.html#AuroraPostgreSQL.Extensions.apg_plan_mgmt)。

## 查询计划管理限制
<a name="AuroraPostgreSQL.Optimize.overview.limitations"></a>

Aurora PostgreSQL 查询计划管理的当前版本存在以下限制。
+ **对于引用系统关系的语句不捕获计划** – 不捕获引用系统关系的语句，如 `pg_class`。这是特意设计的，目的是防止捕获大量由系统生成的供内部使用的计划。这也适用于视图内的系统表。
+ **您的 Aurora PostgreSQL 数据库集群可能需要更大的数据库实例类** - 根据工作负载不同，查询计划管理可能需要具有超过 2 个 vCPU 的数据库实例类。`max_worker_processes` 的数量受数据库实例类大小的限制。2-vCPU 数据库实例类（例如 db.t3.medium）提供的 `max_worker_processes` 的数量可能不足应对给定的工作负载。如果您使用查询计划管理，我们建议您为 Aurora PostgreSQL 数据库集群选择一个具有超过 2 个 vCPU 的数据库实例类。

  如果数据库实例类无法支持工作负载，则查询计划管理会引发一条错误消息，如下所示。

  ```
  WARNING: could not register plan insert background process
  HINT: You may need to increase max_worker_processes.
  ```

  在这种情况下，您应该将 Aurora PostgreSQL 数据库集群纵向扩展到具有更多内存的数据库实例类大小。有关更多信息，请参阅 [数据库实例类支持的数据库引擎](Concepts.DBInstanceClass.SupportAurora.md)。
+ **已存储在会话中的计划不受影响** - 查询计划管理提供了一种在不更改应用程序代码的情况下影响查询计划的方法。但是，如果通用计划已存储在现有会话中，并且要更改其查询计划，则必须先在数据库集群参数组中将 `plan_cache_mode` 设置为 `force_custom_plan`。
+ 在以下情况下，`apg_plan_mgmt.dba_plans` 和 `pg_stat_statements` 中的 `queryid` 可能分叉：
  + 对象存储在 apg\$1plan\$1mgmt.dba\$1plans 中后会被删除并重新创建。
  + `apg_plan_mgmt.plans` 表是从另一个集群导入的。

有关 Aurora PostgreSQL 查询计划管理功能的不同版本的信息，请参阅《Aurora PostgreSQL 版本注释》**中的 [Aurora PostgreSQL apg\$1plan\$1mgmt 扩展版本](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraPostgreSQLReleaseNotes/AuroraPostgreSQL.Extensions.html#AuroraPostgreSQL.Extensions.apg_plan_mgmt)。

## 查询计划管理术语
<a name="AuroraPostgreSQL.Optimize.Start-terminology"></a>

本主题中使用了以下术语。

**托管式语句**  
优化程序在查询计划管理下捕获的 SQL 语句。托管式语句在 `apg_plan_mgmt.dba_plans` 视图中存储了一个或多个查询执行计划。

**计划基准**  
给定托管式语句的一组已批准计划。也就是说，托管式语句在 `status` 视图的 `dba_plan` 列中具有“已批准”状态的所有计划。

**计划历史记录**  
给定托管式语句的所有已捕获计划的集合。计划历史记录包含为该语句捕获的所有计划，无论其状态如何。

**查询计划回归**  
当优化程序选择的计划比在对数据库环境进行给定更改（例如，新的 PostgreSQL 版本或更改统计数据）之前选择的计划更不理想时，就会出现这种情况。

## Aurora PostgreSQL 查询计划管理版本
<a name="AuroraPostgreSQL.Optimize.overview.versions"></a>

所有当前可用的 Aurora PostgreSQL 版本均支持查询计划管理。有关更多信息，请参阅《Aurora PostgreSQL 版本注释》**中的 [Amazon Aurora PostgreSQL 更新](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraPostgreSQLReleaseNotes/AuroraPostgreSQL.Updates.html)的列表。

安装 `apg_plan_mgmt` 扩展时，查询计划管理功能会添加到您的 Aurora PostgreSQL 数据库集群中。不同版本的 Aurora PostgreSQL 支持不同版本的 `apg_plan_mgmt` 扩展。我们建议您将查询计划管理扩展升级到 Aurora PostgreSQL 版本的最新发行版。

**注意**  
有关每个 `apg_plan_mgmt` 扩展版本的版本注释，请参阅《Aurora PostgreSQL 版本注释》**中的 [Aurora PostgreSQL apg\$1plan\$1mgmt 扩展版本](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraPostgreSQLReleaseNotes/AuroraPostgreSQL.Extensions.html#AuroraPostgreSQL.Extensions.apg_plan_mgmt)。

通过使用 `psql` 连接到实例并使用元命令 \$1dx 列出扩展，可以识别集群上运行的版本，如下所示。

```
labdb=> \dx
                       List of installed extensions
     Name      | Version |    Schema     |                            Description
---------------+---------+---------------+-------------------------------------------------------------------
 apg_plan_mgmt | 1.0     | apg_plan_mgmt | Amazon Aurora with PostgreSQL compatibility Query Plan Management
 plpgsql       | 1.0     | pg_catalog    | PL/pgSQL procedural language
(2 rows)
```

输出显示该集群正在使用 1.0 版本的扩展。只有某些 `apg_plan_mgmt` 版本适用于给定的 Aurora PostgreSQL 版本。在某些情况下，您可能需要将 Aurora PostgreSQL 数据库集群升级到新的次要版本或应用补丁，以便可以升级到最新版本的查询计划管理。输出中显示的 `apg_plan_mgmt` 版本 1.0 来自 Aurora PostgreSQL 版本 10.17 数据库集群，该集群没有可用的更高 `apg_plan_mgmt` 版本。在这种情况下，Aurora PostgreSQL 数据库集群应升级到最新版本的 PostgreSQL。

有关将 Aurora PostgreSQL 数据库集群升级到新版本 PostgreSQL 的更多信息，请参阅 [Amazon Aurora PostgreSQL 的数据库引擎更新](AuroraPostgreSQL.Updates.md)。

要了解如何升级 `apg_plan_mgmt` 扩展，请参阅 [升级 Aurora PostgreSQL 查询计划管理](#AuroraPostgreSQL.Optimize.Upgrade)。

## 开启 Aurora PostgreSQL 查询计划管理
<a name="AuroraPostgreSQL.Optimize.Enable"></a>

为 Aurora PostgreSQL 数据库集群设置查询计划管理涉及安装扩展和更改多个数据库集群参数设置。您需要 `rds_superuser` 权限才能安装 `apg_plan_mgmt` 扩展和为 Aurora PostgreSQL 数据库集群开启此功能。

安装该扩展会创建一个新角色 `apg_plan_mgmt`。此角色可让数据库用户查看、管理和维护查询计划。作为具有 `rds_superuser` 权限的管理员，请务必根据需要将 `apg_plan_mgmt` 角色授予数据库用户。

只有具有 `rds_superuser` 角色的用户才能完成以下过程。`rds_superuser` 对于创建 `apg_plan_mgmt` 扩展及其 `apg_plan_mgmt` 角色是必需的。用户必须已授予了 `apg_plan_mgmt` 角色才能管理 `apg_plan_mgmt` 扩展。

**为 Aurora PostgreSQL 数据库集群开启查询计划管理**

以下步骤为提交到 Aurora PostgreSQL 数据库集群的所有 SQL 语句开启查询计划管理。这称为*自动*模式。要了解有关模式之间的差异的更多信息，请参阅 [捕获 Aurora PostgreSQL 执行计划](AuroraPostgreSQL.Optimize.CapturePlans.md)。

1. 通过以下网址打开 Amazon RDS 控制台：[https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/)。

1. 为 Aurora PostgreSQL 数据库集群创建自定义数据库集群参数组。您需要更改某些参数，才能激活查询计划管理并设置其行为。有关更多信息，请参阅 [在 Amazon Aurora 中创建数据库参数组](USER_WorkingWithParamGroups.Creating.md)。

1. 打开自定义数据库集群参数组，并将 `rds.enable_plan_management` 参数设置为 `1`，如下图所示。  
![\[数据库集群参数组的图。\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/images/aurora-qpm-custom-db-cluster-param-change-1.png)

   有关更多信息，请参阅 [在 Amazon Aurora 中修改数据库集群参数组中的参数](USER_WorkingWithParamGroups.ModifyingCluster.md)。

1. 创建自定义数据库参数组，用于在实例级别设置查询计划参数。有关更多信息，请参阅 [在 Amazon Aurora 中创建数据库集群参数组](USER_WorkingWithParamGroups.CreatingCluster.md)。

1. 修改 Aurora PostgreSQL 数据库集群的写入器实例，以使用自定义数据库参数组。有关更多信息，请参阅 [修改数据库集群中的数据库实例](Aurora.Modifying.md#Aurora.Modifying.Instance)。

1. 修改 Aurora PostgreSQL 数据库集群，以使用自定义数据库集群参数组。有关更多信息，请参阅 [使用控制台、CLI 和 API 修改数据库集群](Aurora.Modifying.md#Aurora.Modifying.Cluster)。

1. 重启数据库实例以启用自定义参数组设置。

1. 使用 `psql` 或 `pgAdmin` 连接到 Aurora PostgreSQL 数据库集群的数据库实例端点。以下示例对于 `rds_superuser` 角色使用原定设置 `postgres` 账户。

   ```
   psql --host=cluster-instance-1.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password --dbname=my-db
   ```

1. 为数据库实例创建 `apg_plan_mgmt` 扩展，如下所示。

   ```
   labdb=> CREATE EXTENSION apg_plan_mgmt;
   CREATE EXTENSION
   ```
**提示**  
在应用程序的模板数据库中安装 `apg_plan_mgmt` 扩展。缺省设置模板数据库名为 `template1`。要了解更多信息，请参阅 PostgreSQL 文档中的[模板数据库](https://www.postgresql.org/docs/current/manage-ag-templatedbs.html)。

1. 将 `apg_plan_mgmt.capture_plan_baselines` 参数更改为 `automatic`。此设置使优化程序为已计划或执行两次或更多次的每个 SQL 语句生成计划。
**注意**  
查询计划管理还具有*手动*模式，可用于特定的 SQL 语句。要了解更多信息，请参阅[捕获 Aurora PostgreSQL 执行计划](AuroraPostgreSQL.Optimize.CapturePlans.md)。

1. 将 `apg_plan_mgmt.use_plan_baselines` 参数的值更改为“on”。该参数使优化程序可以从其计划基准中为该语句选择计划。要了解更多信息，请参阅[使用 Aurora PostgreSQL 托管式计划](AuroraPostgreSQL.Optimize.UsePlans.md)。
**注意**  
您可以修改会话的任一动态参数的值，且无需重启实例。

完成查询计划管理的设置后，请务必将 `apg_plan_mgmt` 角色授予需要查看、管理或维护查询计划的任何数据库用户。

## 升级 Aurora PostgreSQL 查询计划管理
<a name="AuroraPostgreSQL.Optimize.Upgrade"></a>

我们建议您将查询计划管理扩展升级到 Aurora PostgreSQL 版本的最新发行版。

1. 以具有 `rds_superuser` 权限的用户身份连接到 Aurora PostgreSQL 数据库集群的写入器实例。如果您在设置实例时保留原定设置名称，则以 `postgres` 身份进行连接。此示例说明如何使用 `psql`，但如果您愿意，也可以使用 pgAdmin。

   ```
   psql --host=111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password
   ```

1. 运行以下查询以升级扩展。

   ```
   ALTER EXTENSION apg_plan_mgmt UPDATE TO '2.1';
   ```

1. 使用 [apg\$1plan\$1mgmt.validate\$1plans](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.validate_plans) 函数更新所有计划的哈希。优化程序会验证所有已批准、未批准和已拒绝的计划，以确保它们仍然是新版本扩展的可行计划。

   ```
   SELECT apg_plan_mgmt.validate_plans('update_plan_hash');
   ```

   要了解有关使用此函数的更多信息，请参阅 [验证计划](AuroraPostgreSQL.Optimize.Deleting.md#AuroraPostgreSQL.Optimize.Maintenance.ValidatingPlans)。

1. 使用 [apg\$1plan\$1mgmt.reload](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.reload) 函数，通过 dba\$1plans 视图中经过验证的计划刷新共享内存中的任何计划。

   ```
   SELECT apg_plan_mgmt.reload();
   ```

要了解有关可用于查询计划管理的所有函数的更多信息，请参阅 [Aurora PostgreSQL 查询计划管理的函数参考](AuroraPostgreSQL.Optimize.Functions.md)。

## 关闭 Aurora PostgreSQL 查询计划管理
<a name="AuroraPostgreSQL.Optimize.Enable.turnoff"></a>

您可以随时通过关闭 `apg_plan_mgmt.use_plan_baselines` 和 `apg_plan_mgmt.capture_plan_baselines` 来禁用查询计划管理。

```
labdb=> SET apg_plan_mgmt.use_plan_baselines = off;

labdb=> SET apg_plan_mgmt.capture_plan_baselines = off;
```

# Aurora PostgreSQL 查询计划管理的最佳实践
<a name="AuroraPostgreSQL.Optimize.BestPractice"></a>

使用查询计划管理功能，您可以控制更改查询执行计划的方式和时间。作为 DBA，使用 QPM 时的主要目标包括防止在数据库发生更改时性能下降，以及控制是否允许优化程序使用新计划。在下面，您可以找到一些使用查询计划管理的推荐最佳实践。主动式和反应式计划管理方法的不同之处在于如何以及何时批准使用新计划。

**Contents**
+ [主动式计划管理有助于防止性能下降](#AuroraPostgreSQL.Optimize.BestPractice.Proactive)
  + [确保主要版本升级后的计划稳定性](#AuroraPostgreSQL.Optimize.BestPractice.MajorVersionUpgrade)
+ [反应式计划管理可检测和修复性能下降](#AuroraPostgreSQL.Optimize.BestPractice.Reactive)

## 主动式计划管理有助于防止性能下降
<a name="AuroraPostgreSQL.Optimize.BestPractice.Proactive"></a>

为了防止出现计划性能倒退，您可以通过运行一个过程来*改进*计划基线，该过程将新发现的计划的性能与已批准计划的现有基线的性能进行比较，然后自动批准最快的一组计划作为新的基线。这样，随着发现更快的计划，计划的基线会随着时间推移而提高。

1. 在开发环境中，确定对性能或系统吞吐量造成最大影响的 SQL 语句。然后捕获这些语句中的计划，如[手动捕获特定 SQL 语句的计划](AuroraPostgreSQL.Optimize.CapturePlans.md#AuroraPostgreSQL.Optimize.CapturePlans.Manual)和[自动捕获计划](AuroraPostgreSQL.Optimize.CapturePlans.md#AuroraPostgreSQL.Optimize.CapturePlans.Automatic)中所述。

1. 将捕获的计划从开发环境导出并导入到生产环境中。有关更多信息，请参阅“[导出和导入 Aurora PostgreSQL 的托管式计划](AuroraPostgreSQL.Optimize.Maintenance.ExportingImporting.md)”。

1. 在生产环境中，运行您的应用程序并强制使用批准的托管计划。有关更多信息，请参阅“[使用 Aurora PostgreSQL 托管式计划](AuroraPostgreSQL.Optimize.UsePlans.md)”。在应用程序运行时，随着优化程序的发现还可添加新计划。有关更多信息，请参阅“[自动捕获计划](AuroraPostgreSQL.Optimize.CapturePlans.md#AuroraPostgreSQL.Optimize.CapturePlans.Automatic)”。

1. 分析未批准的计划并批准那些执行良好的计划。有关更多信息，请参阅“[评估计划性能](AuroraPostgreSQL.Optimize.Maintenance.md#AuroraPostgreSQL.Optimize.Maintenance.EvaluatingPerformance)”。

1. 在应用程序持续运行时，优化程序开始相应使用新计划。

### 确保主要版本升级后的计划稳定性
<a name="AuroraPostgreSQL.Optimize.BestPractice.MajorVersionUpgrade"></a>

PostgreSQL 的每个主要版本都包括对查询优化程序的增强和更改，旨在提高性能。但是，优化器在早期版本中生成的查询执行计划可能会导致较新的升级版本性能下降。在主要版本升级后，您可以使用查询计划管理来解决这些性能问题并确保计划的稳定性。

即使同一个语句存在多个批准计划，优化器也始终使用成本最低的批准计划。升级后，优化器可能会发现新的计划，但它们将被保存为未批准的计划。这些计划只有在使用反应式计划管理和 unapproved\$1plan\$1execution\$1threshold 参数获得批准后才会执行。您可以使用反应式计划管理和 evolve\$1plan\$1baselines 参数来最大限度地提高计划的稳定性。这将新计划的绩效与旧计划的绩效进行比较，然后批准或拒绝比次优计划至少快 10％ 的计划。

升级后，您可以使用 `evolve_plan_baselines` 函数来比较使用查询参数绑定进行升级前后的计划性能。以下步骤假定您一直在生产环境中使用经批准的托管计划，详情请参阅 [使用 Aurora PostgreSQL 托管式计划](AuroraPostgreSQL.Optimize.UsePlans.md)。

1. 升级前，请在运行查询计划管理器的情况下运行应用程序。当应用程序运行时，在优化程序发现新计划时添加它们。有关更多信息，请参阅 [自动捕获计划](AuroraPostgreSQL.Optimize.CapturePlans.md#AuroraPostgreSQL.Optimize.CapturePlans.Automatic)。

1. 评估每个计划的性能。有关更多信息，请参阅 [评估计划性能](AuroraPostgreSQL.Optimize.Maintenance.md#AuroraPostgreSQL.Optimize.Maintenance.EvaluatingPerformance)。

1. 升级后，请再次使用 `evolve_plan_baselines` 函数分析经批准的计划。比较使用查询参数绑定前后的性能。如果新计划较快，您可以将其添加到经批准的计划中。如果它比相同参数绑定的另一个计划更快，那么您可以将较慢的计划标记为“已被拒绝”。

   有关更多信息，请参阅 [批准更好的计划](AuroraPostgreSQL.Optimize.Maintenance.md#AuroraPostgreSQL.Optimize.Maintenance.EvaluatingPerformance.Approving)。有关此函数的参考信息，请参阅[apg\$1plan\$1mgmt.evolve\$1plan\$1baselines](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.evolve_plan_baselines)。

有关更多信息，请参阅[使用 Amazon Aurora PostgreSQL 兼容版查询计划管理确保主要版本升级后性能一致](https://aws.amazon.com/blogs/database/ensuring-consistent-performance-after-major-version-upgrades-with-amazon-aurora-postgresql-query-plan-management/)。

**注意**  
使用逻辑复制或 AWS DMS 执行主要版本升级时，请确保复制 `apg_plan_mgmt` 模式，以确保将现有计划复制到升级后的实例。有关逻辑复制的更多信息，请参阅 [使用逻辑复制对 Aurora PostgreSQL 执行主要版本升级](AuroraPostgreSQL.MajorVersionUpgrade.md)。

## 反应式计划管理可检测和修复性能下降
<a name="AuroraPostgreSQL.Optimize.BestPractice.Reactive"></a>

通过在应用程序运行时进行监控，您可以检测造成性能下降的计划。检测到性能下降时，您可以按照以下步骤手动拒绝或修复糟糕的计划：

1. 在应用程序运行时，强制使用托管计划并自动添加新发现的计划作为未批准的计划。有关更多信息，请参阅“[使用 Aurora PostgreSQL 托管式计划](AuroraPostgreSQL.Optimize.UsePlans.md)”和“[自动捕获计划](AuroraPostgreSQL.Optimize.CapturePlans.md#AuroraPostgreSQL.Optimize.CapturePlans.Automatic)”。

1. 监控正在运行应用程序的性能下降。

1. 在您发现计划性能下降时，请将计划的状态设置为 `rejected`。下次优化程序运行 SQL 语句时，它会自动忽略拒绝的计划，并改为使用不同的已批准计划。有关更多信息，请参阅“[拒绝或禁用速度较慢的计划](AuroraPostgreSQL.Optimize.Maintenance.md#AuroraPostgreSQL.Optimize.Maintenance.EvaluatingPerformance.Rejecting)”。

   在某些情况下，您可能会偏好修复糟糕的计划而不是拒绝、禁用或删除该计划。使用 `pg_hint_plan` 扩展来试验改进计划。通过 `pg_hint_plan`，您使用特殊注释告知优化程序覆盖其通常创建计划的方式。有关更多信息，请参阅 [使用 pg\$1hint\$1plan 修复计划](AuroraPostgreSQL.Optimize.Maintenance.md#AuroraPostgreSQL.Optimize.Maintenance.pg_hint_plan)。

# Aurora PostgreSQL 查询计划管理
<a name="AuroraPostgreSQL.Optimize.Start"></a>

为 Aurora PostgreSQL 数据库集群开启查询计划管理后，优化程序会为其多次处理的任何 SQL 语句生成和存储查询执行计划。优化程序始终将托管式语句首次生成的计划的状态设置为 `Approved`，并将它存储在 `dba_plans` 视图中。

为托管式语句保存的一组已批准计划称为其*计划基准*。随着应用程序运行，优化程序可能会为托管式语句生成其他计划。优化程序将其他捕获的计划的状态设置为 `Unapproved`。

稍后，您可以确定 `Unapproved` 计划的执行是否良好，并将其更改为 `Approved`、`Rejected` 或 `Preferred`。为此，您可以使用 `apg_plan_mgmt.evolve_plan_baselines` 函数或 `apg_plan_mgmt.set_plan_status` 函数。

当优化程序为 SQL 语句生成计划时，查询计划管理会将该计划保存在 `apg_plan_mgmt.plans` 表中。已被授予 `apg_plan_mgmt` 角色的数据库用户可以通过查询 `apg_plan_mgmt.dba_plans` 视图来查看计划详细信息。例如，以下查询列出了非生产 Aurora PostgreSQL 数据库集群的视图中当前计划的详细信息。
+ `sql_hash` – SQL 语句的标识符，它是 SQL 语句的标准化文本的哈希值。
+ `plan_hash` – 计划的唯一标识符，它是 `sql_hash` 和计划的哈希值的组合。
+ `status` – 计划的状态。优化程序可以运行已批准的计划。
+ `enabled` – 指示计划是否准备就绪，可供使用（true）或不可以使用（false）。
+ `plan_outline` – 计划的表示，用于重新创建实际的执行计划。树结构中的运算符映射到 EXPLAIN 输出中的运算符。

`apg_plan_mgmt.dba_plans` 视图具有更多的列，其中包含计划的所有详细信息，例如上次使用计划的时间。有关完整的详细信息，请参阅 [Aurora PostgreSQL 兼容版的 apg\$1plan\$1mgmt.dba\$1plans 视图参考](AuroraPostgreSQL.Optimize.dba_plans_view_Reference.md)。

## 标准化和 SQL 哈希
<a name="AuroraPostgreSQL.Optimize.Start.hash-and-normalization"></a>

在 `apg_plan_mgmt.dba_plans` 视图中，您可以通过 SQL 哈希值来确定托管式语句。SQL 哈希以 SQL 语句的标准化表示形式进行计算，消除了一些差异（例如文本值）。

每条 SQL 语句的*标准化*过程都会保留空格和大小写，以便您仍然可以阅读和理解 SQL 语句的要点。标准化会删除或替换以下项目。
+ 前导块注释
+ EXPLAIN 关键字和 EXPLAIN 选项，以及 EXPLAIN ANALYZE
+ 尾随空格
+ 所有文本

以下面的语句为例。

```
/*Leading comment*/ EXPLAIN SELECT /* Query 1 */ * FROM t WHERE x > 7 AND y = 1; 
```

查询计划管理按以下所示对此语句进行标准化：

```
SELECT /* Query 1 */ * FROM t WHERE x > CONST AND y = CONST; 
```

标准化允许使用相同的 SQL 哈希来处理可能只有文本值或参数值不同的相似 SQL 语本。换句话说，同一个 SQL 哈希可能存在多个计划，在每种不同的条件下都有一个最优计划。

**注意**  
用于不同模式的单个 SQL 语句具有不同的计划，因为它在运行时绑定到特定的模式。计划程序使用有关模式绑定的统计数据来选择最优计划。

要了解有关优化程序如何选择计划的更多信息，请参阅 [使用 Aurora PostgreSQL 托管式计划](AuroraPostgreSQL.Optimize.UsePlans.md)。在该节中，您可以了解到如何在实际使用计划之前使用 `EXPLAIN` 和 `EXPLAIN ANALYZE` 预览计划。有关更多信息，请参阅 [分析优化程序的已选择计划](AuroraPostgreSQL.Optimize.UsePlans.md#AuroraPostgreSQL.Optimize.UsePlans.AnalyzePlans)。有关概述选择计划的过程的图像，请参阅 [优化程序如何选择要运行的计划](AuroraPostgreSQL.Optimize.UsePlans.md#AuroraPostgreSQL.Optimize.UsePlans.ChoosePlans)。

# 捕获 Aurora PostgreSQL 执行计划
<a name="AuroraPostgreSQL.Optimize.CapturePlans"></a>

Aurora PostgreSQL 查询计划管理提供两种不同的模式来捕获查询执行计划：即自动或手动。您可以通过将 `apg_plan_mgmt.capture_plans_baselines` 的值设置为 `automatic` 或 `manual` 来选择模式。您可以使用手动计划捕获为特定的 SQL 语句捕获执行计划。或者，您可以使用自动计划捕获来捕获应用程序运行时多次执行的所有（或者速度最慢）计划。

捕获计划时，优化程序将托管语句首次捕获的计划的状态设置为 `approved`。优化程序将为托管语句捕获的任何其他计划的状态设置为 `unapproved`。但是，有时可能有多个计划保存为 `approved` 状态。在为一个语句并行创建了多个计划并在提交语句的第一个计划之前，可能发生这种情况。

要控制可以捕获并存储在 `dba_plans` 视图中的最大计划数量，请在数据库实例级参数组中设置 `apg_plan_mgmt.max_plans` 参数。修改 `apg_plan_mgmt.max_plans` 参数后需要重启数据库实例，才能让新值生效。有关更多信息，请参阅 [apg\$1plan\$1mgmt.max\$1plans](AuroraPostgreSQL.Optimize.Parameters.md#AuroraPostgreSQL.Optimize.Parameters.max_plans) 参数。

## 手动捕获特定 SQL 语句的计划
<a name="AuroraPostgreSQL.Optimize.CapturePlans.Manual"></a>

如果您已知要管理的 SQL 语句集，请将语句放入 SQL 脚本文件，然后手动捕获计划。下面显示了如何为 SQL 语句集手动捕获查询计划的 psql 示例。

```
psql> SET apg_plan_mgmt.capture_plan_baselines = manual;
psql> \i my-statements.sql 
psql> SET apg_plan_mgmt.capture_plan_baselines = off;
```

在捕获各个 SQL 语句的计划之后，优化程序添加新行到 `apg_plan_mgmt.dba_plans` 视图。

我们建议您在 SQL 脚本文件中使用 EXPLAIN 或 EXPLAIN EXECUTE 语句。请确保在参数值中加入足够的变体以捕获所有感兴趣的计划。

如果您知道比优化程序最低成本计划更好的计划，则可以强制优化程序使用更好的计划。要这样做，请指定一个或多个优化程序提示。有关更多信息，请参阅“[使用 pg\$1hint\$1plan 修复计划](AuroraPostgreSQL.Optimize.Maintenance.md#AuroraPostgreSQL.Optimize.Maintenance.pg_hint_plan)”。要比较 `unapproved` 和 `approved` 计划的性能并批准、拒绝或删除它们，请参阅[评估计划性能](AuroraPostgreSQL.Optimize.Maintenance.md#AuroraPostgreSQL.Optimize.Maintenance.EvaluatingPerformance)。

## 自动捕获计划
<a name="AuroraPostgreSQL.Optimize.CapturePlans.Automatic"></a>

对于类似以下的情况，请使用自动计划捕获：
+ 您不知道要管理的具体 SQL 语句。
+ 您有数百乃至数千个 SQL 语句需要管理。
+ 您的应用程序使用客户端 API。例如，JDBC 使用未命名的预编译语句或者批量模式语句，无法在 psql 中表达。

**自动捕获计划**

1. 通过在数据库实例级参数组中将 `apg_plan_mgmt.capture_plan_baselines` 设置为 `automatic` 来启用自动计划捕获。有关更多信息，请参阅 [在 Amazon Aurora 中修改数据库参数组中的参数](USER_WorkingWithParamGroups.Modifying.md)。

1. 随着应用程序运行，优化程序捕获各个至少运行两次的 SQL 语句的计划。

   随着应用程序使用默认查询计划管理参数设置运行，优化程序捕获各个至少运行两次的 SQL 语句的计划。在使用默认值的同时捕获所有计划具有非常小的运行时开销，并且可在生产中启用。

**禁用自动计划捕获**
+ 从数据库实例级参数组，将 `apg_plan_mgmt.capture_plan_baselines` 参数设置为 `off`。

要评估未批准计划的性能并批准、拒绝或删除这些计划，请参阅[评估计划性能](AuroraPostgreSQL.Optimize.Maintenance.md#AuroraPostgreSQL.Optimize.Maintenance.EvaluatingPerformance)。

# 使用 Aurora PostgreSQL 托管式计划
<a name="AuroraPostgreSQL.Optimize.UsePlans"></a>

要让优化程序为托管语句使用捕获的计划，请将参数 `apg_plan_mgmt.use_plan_baselines` 设置为 `true`。以下是本地实例的示例。

```
SET apg_plan_mgmt.use_plan_baselines = true;
```

当应用程序运行时，此设置会导致优化程序为每个托管式语句使用有效且启用的最低成本、首选或已批准计划。

## 分析优化程序的已选择计划
<a name="AuroraPostgreSQL.Optimize.UsePlans.AnalyzePlans"></a>

当 `apg_plan_mgmt.use_plan_baselines` 参数设置为 `true` 时，您可以使用 EXPLAIN ANALYZE SQL 语句，使优化程序在要运行语句时显示所使用的计划。示例如下：

```
EXPLAIN ANALYZE EXECUTE rangeQuery (1,10000);
```

```
                                                    QUERY PLAN           
--------------------------------------------------------------------------
 Aggregate  (cost=393.29..393.30 rows=1 width=8) (actual time=7.251..7.251 rows=1 loops=1)
   ->  Index Only Scan using t1_pkey on t1 t  (cost=0.29..368.29 rows=10000 width=0) (actual time=0.061..4.859 rows=10000 loops=1)
Index Cond: ((id >= 1) AND (id <= 10000))         
         Heap Fetches: 10000
 Planning time: 1.408 ms
 Execution time: 7.291 ms
 Note: An Approved plan was used instead of the minimum cost plan.
 SQL Hash: 1984047223, Plan Hash: 512153379
```

输出显示了将运行的基准中的已批准计划。但是，输出还显示它发现了更低成本的计划。在这种情况下，您通过启用自动计划捕获（如[自动捕获计划](AuroraPostgreSQL.Optimize.CapturePlans.md#AuroraPostgreSQL.Optimize.CapturePlans.Automatic)中所述），捕获这个最低成本计划。

优化程序始终将新计划捕获为 `Unapproved`。使用 `apg_plan_mgmt.evolve_plan_baselines` 函数可比较计划，并将其更改为已批准、已拒绝或已禁用。有关更多信息，请参阅 [评估计划性能](AuroraPostgreSQL.Optimize.Maintenance.md#AuroraPostgreSQL.Optimize.Maintenance.EvaluatingPerformance)。

## 优化程序如何选择要运行的计划
<a name="AuroraPostgreSQL.Optimize.UsePlans.ChoosePlans"></a>

执行计划的成本是优化程序用于比较不同计划进行的估算。计算计划的成本时，优化程序包括该计划所需的 CPU 和 I/O 操作等因素。要了解有关 PostgreSQL 查询计划程序成本估计的更多信息，请参阅 PostgreSQL 文档中的[查询计划](https://www.postgresql.org/docs/current/runtime-config-query.html)。

下图显示了在查询计划管理处于活动状态以及未处于活动状态时，如何为给定的 SQL 语句选择计划。



![\[Aurora PostgreSQL 查询计划管理工作流\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/images/aurora-query-plan-mgmt_processing-flow.png)


流程如下：

1. 优化程序为 SQL 语句生成最低成本计划。

1. 如果查询计划管理未处于活动状态，则优化程序的计划将立即运行（A. 运行优化程序的计划）。当 `apg_plan_mgmt.capture_plan_baselines` 和 `apg_plan_mgmt.use_plan_baselines` 参数都处于原定设置（分别为“off”和“false”）时，查询计划管理处于非活动状态。

   否则，查询计划管理处于活动状态。在这种情况下，在选择计划之前，将进一步评估 SQL 语句及其优化程序的计划。
**提示**  
具有 `apg_plan_mgmt` 角色的数据库用户可以主动比较计划，更改计划的状态，并根据需要强制使用特定的计划。有关更多信息，请参阅 [改进 Aurora PostgreSQL 查询计划](AuroraPostgreSQL.Optimize.Maintenance.md)。

1. SQL 语句可能已经具有过去由查询计划管理存储的计划。计划以及用于创建这些计划的 SQL 语句的相关信息一起存储在 `apg_plan_mgmt.dba_plans` 中。有关计划的信息包括其状态。计划的状态可以决定是否使用该计划，如下所示。

   1. 如果该计划不在 SQL 语句的存储计划中，这意味着这是优化程序第一次为给定的 SQL 语句生成该特定的计划。该计划将发送到“捕获计划处理（4）”。

   1. 如果该计划在存储的计划中，且其状态为“已批准”或“首选”，则运行该计划（A. 运行优化程序的计划）。

      如果该计划在存储的计划中，但它既不是“已批准”，也不是“首选”，则该计划将发送到“捕获计划处理（4）”。

1. 首次捕获给定 SQL 语句的计划时，该计划的状态始终设置为“已批准（P1）”。如果优化程序随后为同一 SQL 语句生成相同的计划，则该计划的状态将更改为“未批准（P1\$1n）”。

   捕获计划并更新其状态后，将在下一步（5）继续进行评估。

1. 计划的*基准* 由 SQL 语句的历史记录及其在不同状态下的计划组成。查询计划管理可以在选择计划时考虑基准，具体取决于是否开启了使用计划基准选项，如下所示。
   + 当 `apg_plan_mgmt.use_plan_baselines` 参数设置为其原定设置值（`false`）时，“使用计划基准”处于“关闭”状态。该计划在运行之前不会与基准进行比较（A. 运行计划程序的计划）。
   + 当 `apg_plan_mgmt.use_plan_baselines` 参数设置为 `true` 时，“使用计划基准”为“开启”。使用基准（6）进一步评估该计划。

1. 将该计划与基准中用于此语句的其他计划进行比较。

   1. 如果优化程序的计划属于基准中的计划，则检查其状态（7a）。

   1. 如果优化程序的计划不属于基准中的计划，则该计划将作为新的 `Unapproved` 计划添加到语句的计划中。

1. 检查计划的状态以确定其是否为“未批准”。

   1. 如果计划的状态为“未批准”，则将该计划的估计成本与为未批准的执行计划阈值指定的成本估计值进行比较。
      + 如果计划的估计成本低于阈值，则即使它是未批准的计划，优化程序也会使用它（A. 运行优化程序的计划）。通常，优化程序不会运行未批准的计划。但是，当 `apg_plan_mgmt.unapproved_plan_execution_threshold` 参数指定成本阈值时，优化程序会将未批准计划的成本与阈值进行比较。如果估计的成本低于阈值，则优化程序运行此计划。有关更多信息，请参阅 [apg\$1plan\$1mgmt.unapproved\$1plan\$1execution\$1threshold](AuroraPostgreSQL.Optimize.Parameters.md#AuroraPostgreSQL.Optimize.Parameters.unapproved_plan_execution_threshold)。
      + 如果计划的估计成本不低于阈值，则检查该计划的其他属性（8a）。

   1. 如果计划的状态为“未批准”以外的任何状态，则检查它的其他属性（8a）。

1. 优化程序不会使用禁用的计划。也就是其 `enable` 属性设置为“f”（false）的计划。优化程序也不会使用状态为“已拒绝”的计划。

   优化程序无法使用任何无效的计划。随着时间的推移，当计划所依赖的对象（如索引和表分区）被移除或删除时，计划可能会变为无效。

   1. 如果语句具有任何已启用且有效的首选计划，则优化程序从为此 SQL 语句存储的首选计划中选择最低成本计划。然后，优化程序运行最低成本的首选计划。

   1. 如果语句没有任何已启用且有效的首选计划，则将在下一步（9）中对其进行评估。

1. 如果语句具有任何已启用且有效的已批准计划，则优化程序从为此 SQL 语句存储的已批准计划中选择最低成本计划。然后，优化程序运行最低成本的已批准计划。

   如果语句没有任何有效且已启用的已批准计划，则优化程序将使用最低成本计划（A. 运行优化程序的计划）。

# 在 dba\$1plans 视图中检查 Aurora PostgreSQL 查询计划
<a name="AuroraPostgreSQL.Optimize.ViewPlans"></a>

已被授予 `apg_plan_mgmt` 角色的数据库用户和管理员可以查看和管理存储在 `apg_plan_mgmt.dba_plans` 中的计划。Aurora PostgreSQL 数据库集群的管理员（具有 `rds_superuser` 权限的用户）必须将此角色显式授予需要处理查询计划管理的数据库用户。

`apg_plan_mgmt` 视图包含 Aurora PostgreSQL 数据库集群的写入器实例上每个数据库的所有托管式 SQL 语句的计划历史记录。此视图可让您检查计划、计划的状态、上次使用时间以及所有其他相关详细信息。

如[标准化和 SQL 哈希](AuroraPostgreSQL.Optimize.Start.md#AuroraPostgreSQL.Optimize.Start.hash-and-normalization)中所讨论，每个托管式计划均由 SQL 哈希值和计划哈希值的组合来标识。通过这些标识符，您可以使用 Amazon RDS Performance Insights 等工具来跟踪单独计划的性能。有关 Performance Insights 的更多信息，请参阅[使用 Amazon RDS Performance Insights]( https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_PerfInsights.html)。

## 列出托管计划
<a name="AuroraPostgreSQL.Optimize.ViewPlans.List"></a>

要列出托管计划，请在 `apg_plan_mgmt.dba_plans` 视图上使用 SELECT 语句。以下示例显示 `dba_plans` 视图中的一些列，例如 `status`，以标识已批准和未批准计划。

```
SELECT sql_hash, plan_hash, status, enabled, stmt_name 
FROM apg_plan_mgmt.dba_plans; 

 sql_hash   | plan_hash |   status   | enabled | stmt_name
------------+-----------+------------+---------+------------
 1984047223 | 512153379 | Approved   | t       | rangequery 
 1984047223 | 512284451 | Unapproved | t       | rangequery 
 (2 rows)
```

为便于阅读，所显示的查询和输出仅列出了 `dba_plans` 视图中的若干列。有关完整信息，请参阅 [Aurora PostgreSQL 兼容版的 apg\$1plan\$1mgmt.dba\$1plans 视图参考](AuroraPostgreSQL.Optimize.dba_plans_view_Reference.md)。

# 改进 Aurora PostgreSQL 查询计划
<a name="AuroraPostgreSQL.Optimize.Maintenance"></a>

通过评估计划绩效并修复计划来改进查询计划管理。有关改进查询计划的更多信息，请参阅以下主题。

**Topics**
+ [评估计划性能](#AuroraPostgreSQL.Optimize.Maintenance.EvaluatingPerformance)
+ [使用 pg\$1hint\$1plan 修复计划](#AuroraPostgreSQL.Optimize.Maintenance.pg_hint_plan)

## 评估计划性能
<a name="AuroraPostgreSQL.Optimize.Maintenance.EvaluatingPerformance"></a>

在优化程序将计划作为未批准计划捕获之后，使用 `apg_plan_mgmt.evolve_plan_baselines` 函数根据其实际性能来比较计划。根据性能试验的结果，您可以将计划的状态从未批准更改为已批准或已拒绝。如果计划不满足您的要求，您可以改为考虑使用 `apg_plan_mgmt.evolve_plan_baselines` 函数来临时禁用计划。

### 批准更好的计划
<a name="AuroraPostgreSQL.Optimize.Maintenance.EvaluatingPerformance.Approving"></a>

以下示例演示如何使用 `apg_plan_mgmt.evolve_plan_baselines` 函数将托管计划的状态更改为已批准。

```
SELECT apg_plan_mgmt.evolve_plan_baselines (
   sql_hash, 
   plan_hash, 
   min_speedup_factor := 1.0, 
   action := 'approve'
) 
FROM apg_plan_mgmt.dba_plans WHERE status = 'Unapproved';
```

```
NOTICE:     rangequery (1,10000)
NOTICE:     Baseline   [ Planning time 0.761 ms, Execution time 13.261 ms]
NOTICE:     Baseline+1 [ Planning time 0.204 ms, Execution time 8.956 ms]
NOTICE:     Total time benefit: 4.862 ms, Execution time benefit: 4.305 ms
NOTICE:     Unapproved -> Approved
evolve_plan_baselines 
-----------------------
0
(1 row)
```

输出显示 `rangequery` 语句的性能报告，参数绑定 1 和 10,000。新的未批准计划 (`Baseline+1`) 比以前的已批准最佳计划 (`Baseline`) 要好。要确认新计划现在已 `Approved`，请查看 `apg_plan_mgmt.dba_plans` 视图。

```
SELECT sql_hash, plan_hash, status, enabled, stmt_name 
FROM apg_plan_mgmt.dba_plans;
```

```
sql_hash  | plan_hash |  status  | enabled | stmt_name  
------------+-----------+----------+---------+------------
1984047223 | 512153379 | Approved | t       | rangequery
1984047223 | 512284451 | Approved | t       | rangequery
(2 rows)
```

托管计划现在包含两个已批准计划，这些计划是语句的计划基线。您还可以直接调用 `apg_plan_mgmt.set_plan_status` 函数，以直接将计划的状态字段设置为 `'Approved'`、`'Rejected'`、`'Unapproved'` 或 `'Preferred'`。

### 拒绝或禁用速度较慢的计划
<a name="AuroraPostgreSQL.Optimize.Maintenance.EvaluatingPerformance.Rejecting"></a>

要拒绝或禁用计划，请将 `'reject'` 或 `'disable' ` 作为操作参数传递给 `apg_plan_mgmt.evolve_plan_baselines` 函数。此示例禁用任何已捕获并且其速度比语句的最佳 `Unapproved` 计划慢至少 10% 的 `Approved` 计划。

```
SELECT apg_plan_mgmt.evolve_plan_baselines(
sql_hash,  -- The managed statement ID
plan_hash, -- The plan ID
1.1,       -- number of times faster the plan must be 
'disable'  -- The action to take. This sets the enabled field to false.
)
FROM apg_plan_mgmt.dba_plans
WHERE status = 'Unapproved' AND   -- plan is Unapproved
origin = 'Automatic';       -- plan was auto-captured
```

您也可以直接将计划设置为已拒绝或已禁用。要直接将计划的已启用字段设置为 `true` 或 `false`，请调用 `apg_plan_mgmt.set_plan_enabled` 函数。要直接将计划的状态字段设置为 `'Approved'`、`'Rejected'`、`'Unapproved'` 或 `'Preferred'`，请调用 `apg_plan_mgmt.set_plan_status` 函数。

要删除无效和您认为会保持无效的计划，请使用 `apg_plan_mgmt.validate_plans` 函数。此函数可让您删除或禁用无效计划。有关更多信息，请参阅 [验证计划](AuroraPostgreSQL.Optimize.Deleting.md#AuroraPostgreSQL.Optimize.Maintenance.ValidatingPlans)。

## 使用 pg\$1hint\$1plan 修复计划
<a name="AuroraPostgreSQL.Optimize.Maintenance.pg_hint_plan"></a>

查询优化程序经过精心设计，用于查找所有语句的最优计划，大多数情况下优化程序可以找到较好的计划。但是，有时候您可能已知存在比优化程序所生成计划好得多的计划。使优化程序生成所需计划的两种建议方法包括使用 `pg_hint_plan` 扩展，或者在 PostgreSQL 中设置 Grand Unified Configuration (GUC) 变量：
+ `pg_hint_plan` 扩展 – 使用 PostgreSQL 的 `pg_hint_plan` 扩展指定“提示”以修改计划程序的工作方式。要安装 `pg_hint_plan` 扩展并了解有关如何使用该扩展的更多信息，请参阅 [pg\$1hint\$1plan 文档](https://github.com/ossc-db/pg_hint_plan)。
+ GUC 变量 – 覆盖一个或多个成本模型参数或其他优化程序参数，例如 `from_collapse_limit` 或 `GEQO_threshold`。

在您使用这些技术之一来强制查询优化程序使用计划时，您还可以使用查询计划管理来捕获和强制使用新计划。

您可以使用 `pg_hint_plan` 扩展来更改联接顺序、联接方法或者 SQL 语句的访问路径。您使用具有特殊 `pg_hint_plan` 语法的 SQL 注释来修改优化程序如何创建计划。例如，假设问题 SQL 语句具有双向联接。

```
SELECT * 
FROM t1, t2 
WHERE t1.id = t2.id;
```

然后，假设优化程序选择联接顺序（t1、t2），而您知道联接顺序（t2、t1）速度更快。以下提示强制优化程序使用速度更快的联接顺序 (t2, t1)。包括 EXPLAIN，以使优化程序为 SQL 语句生成计划，但不运行语句。（未显示输出。）

```
/*+ Leading ((t2 t1)) */ EXPLAIN SELECT * 
FROM t1, t2 
WHERE t1.id = t2.id;
```

以下步骤显示如何使用 `pg_hint_plan`。

**修改优化程序生成的计划并使用 pg\$1hint\$1plan 捕获计划**

1. 启用手动捕获模式。

   ```
   SET apg_plan_mgmt.capture_plan_baselines = manual;
   ```

1. 指定感兴趣 SQL 语句的提示。

   ```
   /*+ Leading ((t2 t1)) */ EXPLAIN SELECT * 
   FROM t1, t2 
   WHERE t1.id = t2.id;
   ```

   在此语句运行后，优化程序在 `apg_plan_mgmt.dba_plans` 视图中捕获计划。捕获的计划不包括特殊 `pg_hint_plan` 注释语法，因为查询计划管理通过删除前导注释来标准化语句。

1. 使用 `apg_plan_mgmt.dba_plans` 视图查看托管计划。

   ```
   SELECT sql_hash, plan_hash, status, sql_text, plan_outline 
   FROM apg_plan_mgmt.dba_plans;
   ```

1. 将计划的状态设置为 `Preferred`。这样做可以确保优化程序将选择运行它，而不是在最低成本计划未处于 `Approved` 或 `Preferred` 状态时从一组已批准计划中选择。

   ```
   SELECT apg_plan_mgmt.set_plan_status(sql-hash, plan-hash, 'preferred' ); 
   ```

1. 禁用手动计划捕获并强制托管计划的使用。

   ```
   SET apg_plan_mgmt.capture_plan_baselines = false;
   SET apg_plan_mgmt.use_plan_baselines = true;
   ```

   现在，当原始 SQL 语句运行时，优化程序将选择 `Approved` 或 `Preferred` 计划。如果最低成本计划不是 `Approved` 或 `Preferred`，则优化程序将选择 `Preferred` 计划。

# 删除 Aurora PostgreSQL 查询计划
<a name="AuroraPostgreSQL.Optimize.Deleting"></a>

删除未使用的执行计划或无效的计划。有关删除计划的更多信息，请参阅以下各节。

**Topics**
+ [删除计划](#AuroraPostgreSQL.Optimize.Maintenance.DeletingPlans)
+ [验证计划](#AuroraPostgreSQL.Optimize.Maintenance.ValidatingPlans)

## 删除计划
<a name="AuroraPostgreSQL.Optimize.Maintenance.DeletingPlans"></a>

如果计划已超过一个月（具体来说，为 32天）未使用，则会自动删除。这是 `apg_plan_mgmt.plan_retention_period` 参数的原定设置。您可以将计划保留期更改为较长的时间段，也可以更改为从值 1 开始的较短时间段。通过从当前日期中减去 `last_used` 日期来计算自上次使用计划以来的天数。`last_used` 日期是优化程序选择计划作为最低成本计划或运行该计划的最近日期。计划的这一日期存储在 `apg_plan_mgmt.dba_plans` 视图中。

建议您删除长时间未使用或者无用的计划。每个计划都具有 `last_used` 日期，优化程序在每次执行某个计划或选择计划作为语句的最低成本计划时，都会更新该日期。检查上次 `last_used` 日期以确定可以安全删除的计划。

以下查询返回一个具有三列的表，其中包含有关计划总数、无法删除的计划数和成功删除的计划数的计数。此查询有一个嵌套查询示例，旨在说明如何使用 `apg_plan_mgmt.delete_plan` 函数来删除过去 31 天内未选为最低成本计划且其状态不为 `Rejected` 的所有计划。

```
SELECT (SELECT COUNT(*) from apg_plan_mgmt.dba_plans) total_plans,
       COUNT(*) FILTER (WHERE result = -1) failed_to_delete,
       COUNT(*) FILTER (WHERE result = 0) successfully_deleted
       FROM (
            SELECT apg_plan_mgmt.delete_plan(sql_hash, plan_hash) as result
            FROM apg_plan_mgmt.dba_plans
            WHERE last_used < (current_date - interval '31 days')
            AND status <> 'Rejected'
            ) as dba_plans ;
```

```
 total_plans | failed_to_delete | successfully_deleted
-------------+------------------+----------------------
           3 |                0 |                    2
```

有关更多信息，请参阅 [apg\$1plan\$1mgmt.delete\$1plan](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.delete_plan)。

要删除无效和您认为会保持无效的计划，请使用 `apg_plan_mgmt.validate_plans` 函数。此函数可让您删除或禁用无效计划。有关更多信息，请参阅 [验证计划](#AuroraPostgreSQL.Optimize.Maintenance.ValidatingPlans)。

**重要**  
如果您未删除多余的计划，则最终可能会耗尽为查询计划管理留出的共享内存。要控制可供托管计划使用的内存量，请使用 `apg_plan_mgmt.max_plans` 参数。在自定义数据库参数组中设置此参数并重启数据库实例，让更改生效。有关更多信息，请参阅 [apg\$1plan\$1mgmt.max\$1plans](AuroraPostgreSQL.Optimize.Parameters.md#AuroraPostgreSQL.Optimize.Parameters.max_plans) 参数。

## 验证计划
<a name="AuroraPostgreSQL.Optimize.Maintenance.ValidatingPlans"></a>

使用 `apg_plan_mgmt.validate_plans` 函数来删除或禁用无效的计划。

在删除了所依赖的对象（例如索引或表）时，托管计划会成为无效或过时。但是，如果重新创建了删除的对象，计划可能仅临时无效。如果某个无效计划以后会变成有效，建议您禁用无效的计划或者不执行任何操作，而不是删除它。

要查找并删除所有无效且在过去一周中未使用的计划，请使用 `apg_plan_mgmt.validate_plans `函数，如下所示。

```
SELECT apg_plan_mgmt.validate_plans(sql_hash, plan_hash, 'delete') 
FROM apg_plan_mgmt.dba_plans
WHERE last_used < (current_date - interval '7 days');
```

要直接启用或禁用计划，请使用 `apg_plan_mgmt.set_plan_enabled` 函数。

# 导出和导入 Aurora PostgreSQL 的托管式计划
<a name="AuroraPostgreSQL.Optimize.Maintenance.ExportingImporting"></a>

您可以导出托管计划并将其导入到其他数据库实例。

**导出托管计划**  
授权用户可以将 `apg_plan_mgmt.plans` 表的任意子集复制到其他表，然后使用 `pg_dump` 命令来保存。以下是示例。

```
CREATE TABLE plans_copy AS SELECT * 
FROM apg_plan_mgmt.plans [ WHERE predicates ] ;
```

```
% pg_dump --table apg_plan_mgmt.plans_copy -Ft mysourcedatabase > plans_copy.tar
```

```
DROP TABLE apg_plan_mgmt.plans_copy;
```

**导入托管计划**

1. 将所导出的托管计划的 .tar 文件，复制到将要还原计划的系统中。

1. 使用 `pg_restore` 命令将 tar 文件复制到新表。

   ```
   % pg_restore --dbname mytargetdatabase -Ft plans_copy.tar
   ```

1. 将 `plans_copy` 表与 `apg_plan_mgmt.plans` 表合并，如以下示例所示。
**注意**  
有些情况下，您可能从 `apg_plan_mgmt` 扩展的一个版本转储并还原到其他版本。在这些情况下，计划表中的列可能不同。如果是这样，明确命名列而不是使用 SELECT \$1。

   ```
   INSERT INTO apg_plan_mgmt.plans SELECT * FROM plans_copy
    ON CONFLICT ON CONSTRAINT plans_pkey
    DO UPDATE SET
    status = EXCLUDED.status,
    enabled = EXCLUDED.enabled,
    -- Save the most recent last_used date 
    --
    last_used = CASE WHEN EXCLUDED.last_used > plans.last_used 
    THEN EXCLUDED.last_used ELSE plans.last_used END, 
    -- Save statistics gathered by evolve_plan_baselines, if it ran:
    --
    estimated_startup_cost = EXCLUDED.estimated_startup_cost,
    estimated_total_cost = EXCLUDED.estimated_total_cost,
    planning_time_ms = EXCLUDED.planning_time_ms,
    execution_time_ms = EXCLUDED.execution_time_ms,
    total_time_benefit_ms = EXCLUDED.total_time_benefit_ms, 
    execution_time_benefit_ms = EXCLUDED.execution_time_benefit_ms;
   ```

1. 将托管计划重新加载到共享内存中，删除临时计划表。

   ```
   SELECT apg_plan_mgmt.reload(); -- refresh shared memory
   DROP TABLE plans_copy;
   ```

# Aurora PostgreSQL 查询计划管理的参数参考
<a name="AuroraPostgreSQL.Optimize.Parameters"></a>

您可以使用本节中列出的参数设置 `apg_plan_mgmt` 扩展的首选项。这些参数可在自定义数据库集群参数以及与 Aurora PostgreSQL 数据库集群关联的数据库参数组中使用。这些参数控制查询计划管理功能的行为及其影响优化程序的方式。有关设置查询计划管理的信息，请参阅[开启 Aurora PostgreSQL 查询计划管理](AuroraPostgreSQL.Optimize.overview.md#AuroraPostgreSQL.Optimize.Enable)。如果没有按照本节中的详细说明设置 `apg_plan_mgmt` 扩展，则更改以下参数将不起作用。有关修改参数的信息，请参阅[在 Amazon Aurora 中修改数据库集群参数组中的参数](USER_WorkingWithParamGroups.ModifyingCluster.md)和[Amazon Aurora 数据库实例的数据库参数组](USER_WorkingWithDBInstanceParamGroups.md)。

**Topics**
+ [apg\$1plan\$1mgmt.capture\$1plan\$1baselines](#AuroraPostgreSQL.Optimize.Parameters.capture_plan_baselines)
+ [apg\$1plan\$1mgmt.plan\$1capture\$1threshold](#AuroraPostgreSQL.Optimize.Parameters.plan_capture_threshold)
+ [apg\$1plan\$1mgmt.explain\$1hashes](#AuroraPostgreSQL.Optimize.Parameters.explain_hashes)
+ [apg\$1plan\$1mgmt.log\$1plan\$1enforcement\$1result](#AuroraPostgreSQL.Optimize.Parameters.log_plan_enforcement_result)
+ [apg\$1plan\$1mgmt.max\$1databases](#AuroraPostgreSQL.Optimize.Parameters.max_databases)
+ [apg\$1plan\$1mgmt.max\$1plans](#AuroraPostgreSQL.Optimize.Parameters.max_plans)
+ [apg\$1plan\$1mgmt.plan\$1hash\$1version](#AuroraPostgreSQL.Optimize.Parameters.plan_hash_version)
+ [apg\$1plan\$1mgmt.plan\$1retention\$1period](#AuroraPostgreSQL.Optimize.Parameters.plan_retention_period)
+ [apg\$1plan\$1mgmt.unapproved\$1plan\$1execution\$1threshold](#AuroraPostgreSQL.Optimize.Parameters.unapproved_plan_execution_threshold)
+ [apg\$1plan\$1mgmt.use\$1plan\$1baselines](#AuroraPostgreSQL.Optimize.Parameters.use_plan_baselines)
+ [auto\$1explain.hashes](#AuroraPostgreSQL.Optimize.Parameters.auto_explain.hashes)

## apg\$1plan\$1mgmt.capture\$1plan\$1baselines
<a name="AuroraPostgreSQL.Optimize.Parameters.capture_plan_baselines"></a>

捕获优化程序为每条 SQL 语句生成的查询执行计划，并将它们存储在 `dba_plans` 视图中。原定设置情况下，可存储的最大计划数为 10000（由 `apg_plan_mgmt.max_plans` 参数指定）。有关参考信息，请参阅 [apg\$1plan\$1mgmt.max\$1plans](#AuroraPostgreSQL.Optimize.Parameters.max_plans)。

您可以在自定义数据库集群参数组或自定义数据库参数组中设置此参数。更改此参数的值不需要重启。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Optimize.Parameters.html)

有关更多信息，请参阅 [捕获 Aurora PostgreSQL 执行计划](AuroraPostgreSQL.Optimize.CapturePlans.md)。

## apg\$1plan\$1mgmt.plan\$1capture\$1threshold
<a name="AuroraPostgreSQL.Optimize.Parameters.plan_capture_threshold"></a>

指定一个阈值，这样如果查询执行计划的总成本低于该阈值，便不会在 `apg_plan_mgmt.dba_plans` 视图中捕获该计划。

更改此参数的值不需要重启。


| 默认值 | 允许值 | 说明 | 
| --- | --- | --- | 
| 0 | 0 - 1.79769e\$1308 | 设置用于捕获计划的 `apg_plan_mgmt` 查询计划总执行成本的阈值。  | 

有关更多信息，请参阅 [在 dba\$1plans 视图中检查 Aurora PostgreSQL 查询计划](AuroraPostgreSQL.Optimize.ViewPlans.md)。

## apg\$1plan\$1mgmt.explain\$1hashes
<a name="AuroraPostgreSQL.Optimize.Parameters.explain_hashes"></a>

指定 `EXPLAIN [ANALYZE]` 是否在其输出的结尾显示 `sql_hash` 和 `plan_hash`。更改此参数的值不需要重启。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Optimize.Parameters.html)

## apg\$1plan\$1mgmt.log\$1plan\$1enforcement\$1result
<a name="AuroraPostgreSQL.Optimize.Parameters.log_plan_enforcement_result"></a>

指定是否必须记录结果，以查看 QPM 托管式计划是否得到正确使用。使用存储的通用计划时，日志文件中不会写入任何记录。更改此参数的值不需要重启。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Optimize.Parameters.html)

## apg\$1plan\$1mgmt.max\$1databases
<a name="AuroraPostgreSQL.Optimize.Parameters.max_databases"></a>

在您的 Aurora PostgreSQL 数据库集群的写入器实例上，指定可以使用查询计划管理的最大数据库数量。原定设置情况下，最多 10 个数据库可以使用查询计划管理。如果实例上的数据库数量超过 10 个，则可以更改此设置的值。要了解给定实例上有多少数据库，请使用 `psql` 连接到该实例。然后，使用 psql 元命令 `\l` 列出数据库。

更改此参数的值要求您重启实例才能使设置生效。


| 默认值 | 允许值 | 说明 | 
| --- | --- | --- | 
| 10 | 10-2147483647 | 实例上可以使用查询计划管理的最大数据库数量。 | 

您可以在自定义数据库集群参数组或自定义数据库参数组中设置此参数。

## apg\$1plan\$1mgmt.max\$1plans
<a name="AuroraPostgreSQL.Optimize.Parameters.max_plans"></a>

设置查询计划管理器可以在 `apg_plan_mgmt.dba_plans` 视图中维持的 SQL 语句的最大数量。我们建议为所有的 Aurora PostgreSQL 版本将此参数设置为 `10000` 或更高的值。

您可以在自定义数据库集群参数组或自定义数据库参数组中设置此参数。更改此参数的值要求您重启实例才能使设置生效。


| 默认值 | 允许值 | 说明 | 
| --- | --- | --- | 
| 10000 | 10-2147483647 | `apg_plan_mgmt.dba_plans` 视图中可存储的最大计划数。 Aurora PostgreSQL 版本 10 及更早版本的原定设置值为 1000。  | 

有关更多信息，请参阅 [在 dba\$1plans 视图中检查 Aurora PostgreSQL 查询计划](AuroraPostgreSQL.Optimize.ViewPlans.md)。

## apg\$1plan\$1mgmt.plan\$1hash\$1version
<a name="AuroraPostgreSQL.Optimize.Parameters.plan_hash_version"></a>

指定 plan\$1hash 计算旨在涵盖的使用案例。`apg_plan_mgmt.plan_hash_version` 的较高版本涵盖了较低版本的所有功能。例如，版本 3 涵盖了版本 2 支持的使用案例。

 更改此参数的值后，必须调用 `apg_plan_mgmt.validate_plans('update_plan_hash')`。它使用安装的 apg\$1plan\$1mgmt 和 plans 表中的条目更新每个数据库中的 plan\$1hash 值。有关更多信息，请参阅 [验证计划](AuroraPostgreSQL.Optimize.Deleting.md#AuroraPostgreSQL.Optimize.Maintenance.ValidatingPlans)。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Optimize.Parameters.html)

## apg\$1plan\$1mgmt.plan\$1retention\$1period
<a name="AuroraPostgreSQL.Optimize.Parameters.plan_retention_period"></a>

指定要在 `apg_plan_mgmt.dba_plans` 视图中保留计划的天数，此天数之后将自动删除计划。原定设置情况下，自上次使用计划（`apg_plan_mgmt.dba_plans` 视图中的 `last_used` 列）起 32 天后，计划将被删除。您可以将此设置更改为任意数字，1 及更多。

更改此参数的值要求您重启实例才能使设置生效。


| 默认值 | 允许值 | 说明 | 
| --- | --- | --- | 
| 32 | 1-2147483647 | 自上次使用计划后至删除计划的最大天数。 | 

有关更多信息，请参阅 [在 dba\$1plans 视图中检查 Aurora PostgreSQL 查询计划](AuroraPostgreSQL.Optimize.ViewPlans.md)。

## apg\$1plan\$1mgmt.unapproved\$1plan\$1execution\$1threshold
<a name="AuroraPostgreSQL.Optimize.Parameters.unapproved_plan_execution_threshold"></a>

指定一个成本阈值，如果低于该阈值，优化器可以使用未批准的计划。默认情况下，该阈值为 0，所以优化器不运行未批准的计划。将此参数设置为极低的成本阈值（例如 100）可以避免普通计划的计划实施开销。您也可以使用反应式计划管理将此参数设置为一个非常大的值，比如 10000000。这样，优化器就可以在没有计划实施开销的情况下使用所有选定的计划。但是，当发现错误的计划时，您可以手动将其标记为“已拒绝”，这样下次就不会使用该计划。

此参数的值表示运行给定计划的成本估计。如果未批准的计划低于该估计成本，则优化程序会将其用于 SQL 语句。您可以在 `dba_plans` 视图中查看已捕获的计划及其状态（已批准、未批准）。要了解更多信息，请参阅[在 dba\$1plans 视图中检查 Aurora PostgreSQL 查询计划](AuroraPostgreSQL.Optimize.ViewPlans.md)。

更改此参数的值不需要重启。


| 默认值 | 允许值 | 说明 | 
| --- | --- | --- | 
| 0 | 0-2147483647 | 估计的计划开销，如果低于该值，则将使用未批准的计划。 | 

有关更多信息，请参阅 [使用 Aurora PostgreSQL 托管式计划](AuroraPostgreSQL.Optimize.UsePlans.md)。

## apg\$1plan\$1mgmt.use\$1plan\$1baselines
<a name="AuroraPostgreSQL.Optimize.Parameters.use_plan_baselines"></a>

指定优化程序应使用捕获的并存储在 `apg_plan_mgmt.dba_plans` 视图中的已批准计划之一。原定设置情况下，此参数处于关闭状态（false），这会导致优化程序使用其生成的最低成本计划，而无需进行任何进一步评估。启用此参数（将其设置为 true）会强制优化程序从其计划基准中为该语句选择查询执行计划。有关更多信息，请参阅 [使用 Aurora PostgreSQL 托管式计划](AuroraPostgreSQL.Optimize.UsePlans.md)。要查找详细说明此过程的图像，请参阅[优化程序如何选择要运行的计划](AuroraPostgreSQL.Optimize.UsePlans.md#AuroraPostgreSQL.Optimize.UsePlans.ChoosePlans)。

您可以在自定义数据库集群参数组或自定义数据库参数组中设置此参数。更改此参数的值不需要重启。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Optimize.Parameters.html)

您可以根据需要，评估不同的已捕获计划的响应时间以及变更计划状态。有关更多信息，请参阅 [改进 Aurora PostgreSQL 查询计划](AuroraPostgreSQL.Optimize.Maintenance.md)。

## auto\$1explain.hashes
<a name="AuroraPostgreSQL.Optimize.Parameters.auto_explain.hashes"></a>

指定 auto\$1explain 输出是否显示 sql\$1hash 和 plan\$1hash。更改此参数的值不需要重启。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Optimize.Parameters.html)

# Aurora PostgreSQL 查询计划管理的函数参考
<a name="AuroraPostgreSQL.Optimize.Functions"></a>

`apg_plan_mgmt` 扩展提供以下函数。

**Topics**
+ [apg\$1plan\$1mgmt.copy\$1outline](#AuroraPostgreSQL.Optimize.Functions.copy_outline)
+ [apg\$1plan\$1mgmt.delete\$1plan](#AuroraPostgreSQL.Optimize.Functions.delete_plan)
+ [apg\$1plan\$1mgmt.evolve\$1plan\$1baselines](#AuroraPostgreSQL.Optimize.Functions.evolve_plan_baselines)
+ [apg\$1plan\$1mgmt.get\$1explain\$1plan](#AuroraPostgreSQL.Optimize.Functions.get_explain_plan)
+ [apg\$1plan\$1mgmt.plan\$1last\$1used](#AuroraPostgreSQL.Optimize.Functions.plan_last_used)
+ [apg\$1plan\$1mgmt.reload](#AuroraPostgreSQL.Optimize.Functions.reload)
+ [apg\$1plan\$1mgmt.set\$1plan\$1enabled](#AuroraPostgreSQL.Optimize.Functions.set_plan_enabled)
+ [apg\$1plan\$1mgmt.set\$1plan\$1status](#AuroraPostgreSQL.Optimize.Functions.set_plan_status)
+ [apg\$1plan\$1mgmt.update\$1plans\$1last\$1used](#AuroraPostgreSQL.Optimize.Functions.update_plans_last_used)
+ [apg\$1plan\$1mgmt.validate\$1plans](#AuroraPostgreSQL.Optimize.Functions.validate_plans)

## apg\$1plan\$1mgmt.copy\$1outline
<a name="AuroraPostgreSQL.Optimize.Functions.copy_outline"></a>

将给定的 SQL 计划哈希和计划大纲复制到目标 SQL 计划哈希和大纲，从而覆盖目标的计划哈希和大纲。此功能在 `apg_plan_mgmt` 2.3 及更高版本中可用。

**语法**

```
apg_plan_mgmt.copy_outline(
    source_sql_hash,
    source_plan_hash,
    target_sql_hash,
    target_plan_hash,
    force_update_target_plan_hash
)
```

**返回值**  
复制成功时返回 0。对于无效输入引发异常。

**参数**


****  

| 参数 | 说明 | 
| --- | --- | 
| source\$1sql\$1hash  | 要复制到目标查询的与 plan\$1hash 关联的 sql\$1hash ID。 | 
| source\$1plan\$1hash  | 要复制到目标查询的 plan\$1hash ID。 | 
| target\$1sql\$1hash | 要使用源计划哈希和大纲更新的查询的 sql\$1hash ID。 | 
| target\$1plan\$1hash | 要使用源计划哈希和大纲更新的查询的 plan\$1hash ID。 | 
| force\$1update\$1target\$1plan\$1hash | （可选）即使源计划对 target\$1sql\$1hash 不可重现，查询的 target\$1plan\$1hash ID 也会更新。设置为 True 时，该函数可用于在关系名称和列一致的架构之间复制计划。 | 

**使用说明**：

此函数允许您将使用提示的计划哈希和计划大纲复制到其他类似语句，从而无需在目标语句中每次出现时都使用内联提示语句。如果更新的目标查询导致计划无效，则此函数会引发错误并回滚尝试的更新。

## apg\$1plan\$1mgmt.delete\$1plan
<a name="AuroraPostgreSQL.Optimize.Functions.delete_plan"></a>

删除托管计划。

**语法**

```
apg_plan_mgmt.delete_plan(
    sql_hash,
    plan_hash
)
```

**返回值**  
如果删除成功则返回 0，如果删除失败则返回 -1。

**参数**


****  

| 参数 | 描述 | 
| --- | --- | 
| sql\$1hash  | 计划的托管 SQL 语句的 sql\$1hash ID。 | 
| plan\$1hash | 托管计划的 plan\$1hash ID。 | 

 

## apg\$1plan\$1mgmt.evolve\$1plan\$1baselines
<a name="AuroraPostgreSQL.Optimize.Functions.evolve_plan_baselines"></a>

验证已经批准的计划速度是否更快，或者查询优化程序确定作为最低成本计划的计划是否速度更快。

**语法**

```
apg_plan_mgmt.evolve_plan_baselines(
    sql_hash, 
    plan_hash,
    min_speedup_factor,
    action
)
```

**返回值**

速度比最佳已批准计划要慢的计划数量。

**参数**


****  

| 参数 | 描述 | 
| --- | --- | 
| sql\$1hash | 计划的托管 SQL 语句的 sql\$1hash ID。 | 
| plan\$1hash | 托管计划的 plan\$1hash ID。使用 NULL 表示所有计划具有相同的 sql\$1hash ID 值。 | 
| min\$1speedup\$1factor |  *最低加速系数*可能是计划必须比已经批准的最佳计划要快的倍数，达到此数字才能批准计划。或者，此系数可以是比计划必须达到才能拒绝或禁用它的速度慢的倍数。 这是正浮点数值。  | 
| action |  函数执行的操作。包括下列有效值。大小写没有影响。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Optimize.Functions.html)  | 

**使用说明**

根据规划加上执行时间是否比最佳已批准计划速度快（达到您设置的系数），将特定计划设置为已批准、已拒绝或已禁用。操作参数可以设置为 `'approve'` 或 `'reject'` 以自动批准或拒绝满足性能标准的计划。此外，可以将其设置为 ''（空字符串）以进行性能试验并生成报告，但不采取操作。

您可以避免无目标地为 `apg_plan_mgmt.evolve_plan_baselines` 函数近期在其中运行的计划重新运行此函数。要这样做，将计划限制为仅近期创建的未批准计划。此外，您可以避免在任何具有近期 `apg_plan_mgmt.evolve_plan_baselines` 时间戳的已批准计划上运行 `last_verified` 函数。

开展性能试验，以将各个计划的规划加上执行时间，相对于基线中的其他计划进行比较。部分情况下，某个语句只有一个计划并且该计划已批准。在这种情况下，将计划的规划加上执行时间，与不使用计划时的规划加上执行时间进行比较。

各个计划增加的好处（或坏处）记录在 `apg_plan_mgmt.dba_plans` 视图的 `total_time_benefit_ms` 列中。当此值为正数时，有可衡量的性能优势，可以将此计划包括在基线内。

除了收集各个候选计划的规划和执行时间之外，使用 `last_verified` 来更新 `apg_plan_mgmt.dba_plans` 视图的 `current_timestamp` 列。`last_verified` 时间戳可用于避免对某个最近已经验证了其性能的计划，再次运行此函数。

## apg\$1plan\$1mgmt.get\$1explain\$1plan
<a name="AuroraPostgreSQL.Optimize.Functions.get_explain_plan"></a>

为指定的 SQL 语句生成 `EXPLAIN` 语句文本。

**语法**

```
apg_plan_mgmt.get_explain_plan(
    sql_hash,
    plan_hash,
    [explainOptionList]
)
```

**返回值**  
返回指定 SQL 语句的运行时统计数据。使用不带 `explainOptionList` 以返回一个简单的 `EXPLAIN` 计划。

**参数**


****  

| 参数 | 描述 | 
| --- | --- | 
| sql\$1hash  | 计划的托管 SQL 语句的 sql\$1hash ID。 | 
| plan\$1hash | 托管计划的 plan\$1hash ID。 | 
| explainOptionList | 逗号分隔的解释选项列表。有效值包括 `'analyze'`、`'verbose'`、`'buffers'`、`'hashes'` 和 `'format json'`。如果 `explainOptionList` 列表为 NULL 或空字符串 ('')，此函数会生成 `EXPLAIN` 语句，不带任何统计数据。  | 

 

**使用说明**

对于 `explainOptionList`，您可以使用与 `EXPLAIN` 语句一起使用的任何相同选项。Aurora PostgreSQL 优化程序将您为 `EXPLAIN` 语句提供的选项列表连接在一起。

## apg\$1plan\$1mgmt.plan\$1last\$1used
<a name="AuroraPostgreSQL.Optimize.Functions.plan_last_used"></a>

从共享内存返回指定计划的 `last_used` 日期。

**注意**  
数据库集群中的主数据库实例上共享内存中的值始终为最新值。该值仅定期刷新到 `apg_plan_mgmt.dba_plans` 视图的 `last_used` 列中。

**语法**

```
apg_plan_mgmt.plan_last_used(
    sql_hash,
    plan_hash
)
```

**返回值**  
返回 `last_used` 日期。

**参数**


****  

| 参数 | 描述 | 
| --- | --- | 
| sql\$1hash  | 计划的托管 SQL 语句的 sql\$1hash ID。 | 
| plan\$1hash | 托管计划的 plan\$1hash ID。 | 

 

## apg\$1plan\$1mgmt.reload
<a name="AuroraPostgreSQL.Optimize.Functions.reload"></a>

将计划从 `apg_plan_mgmt.dba_plans` 视图重新加载到共享内存中。

**语法**

```
apg_plan_mgmt.reload()
```

**返回值**

无。

**参数**

无。

**使用说明**

对于以下情况，调用 `reload`：
+ 使用它来立即刷新只读副本的共享内存，而不是等待新计划传播到副本。
+ 在导入托管计划后使用它。



## apg\$1plan\$1mgmt.set\$1plan\$1enabled
<a name="AuroraPostgreSQL.Optimize.Functions.set_plan_enabled"></a>

启用或禁用托管计划。

**语法**

```
apg_plan_mgmt.set_plan_enabled(
    sql_hash, 
    plan_hash, 
    [true | false]
)
```

**返回值**

如果设置成功则返回 0，如果设置失败则返回 -1。

**参数**


****  

| 参数 | 描述 | 
| --- | --- | 
| sql\$1hash | 计划的托管 SQL 语句的 sql\$1hash ID。 | 
| plan\$1hash | 托管计划的 plan\$1hash ID。 | 
| enabled |  布尔值 true 或 false： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Optimize.Functions.html)  | 

 

## apg\$1plan\$1mgmt.set\$1plan\$1status
<a name="AuroraPostgreSQL.Optimize.Functions.set_plan_status"></a>

将托管计划的状态设置为 `Approved`、`Unapproved`、`Rejected` 或 `Preferred`。

**语法**

```
apg_plan_mgmt.set_plan_status(
    sql_hash, 
    plan_hash, 
    status
)
```

**返回值**

如果设置成功则返回 0，如果设置失败则返回 -1。

**参数**


****  

| 参数 | 描述 | 
| --- | --- | 
| sql\$1hash | 计划的托管 SQL 语句的 sql\$1hash ID。 | 
| plan\$1hash | 托管计划的 plan\$1hash ID。 | 
| status |  具有以下值之一的字符串： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Optimize.Functions.html) 您使用的大小写并不重要，但 `apg_plan_mgmt.dba_plans` 视图中的状态值设置为首字母大写。有关这些值的更多信息，请参阅 `status`中的 [Aurora PostgreSQL 兼容版的 apg\$1plan\$1mgmt.dba\$1plans 视图参考](AuroraPostgreSQL.Optimize.dba_plans_view_Reference.md)。  | 

 

## apg\$1plan\$1mgmt.update\$1plans\$1last\$1used
<a name="AuroraPostgreSQL.Optimize.Functions.update_plans_last_used"></a>

立即使用存储在共享内存中的 `last_used` 日期更新计划表。

**语法**

```
apg_plan_mgmt.update_plans_last_used()
```

**返回值**

无。

**参数**

无。

**使用说明**

调用 `update_plans_last_used` 以确保针对 `dba_plans.last_used` 列的查询使用最新的信息。如果 `last_used` 日期不会立即更新，后台进程会使用 `last_used` 日期每小时更新一次计划表（预设情况下）。

例如，如果具有某个特定 `sql_hash` 的语句开始运行缓慢，您可以确定自性能下降开始以来为该语句执行了哪些计划。为此，首先将共享内存中的数据刷新到磁盘，使 `last_used` 日期保持最新，然后查询性能下降的语句的 `sql_hash` 的所有计划。在查询中，请确保 `last_used` 日期大于或等于性能下降的开始日期。该查询将标识可能对性能下降负责的计划或一组计划。您可以使用 `explainOptionList` 被设置为 `verbose, hashes` 的 `apg_plan_mgmt.get_explain_plan`。您还可以使用 `apg_plan_mgmt.evolve_plan_baselines` 分析计划以及任何可能表现更好的替代计划。

`update_plans_last_used` 函数仅对数据库集群的主数据库实例具有影响。

## apg\$1plan\$1mgmt.validate\$1plans
<a name="AuroraPostgreSQL.Optimize.Functions.validate_plans"></a>

验证优化程序仍可重新创建计划。优化程序将验证 `Approved`、`Unapproved` 和 `Preferred` 计划，而无论是启用还是禁用了此计划。不验证 `Rejected` 计划。（可选）您可以使用 `apg_plan_mgmt.validate_plans` 函数来删除或禁用无效计划。

**语法**

```
apg_plan_mgmt.validate_plans(
    sql_hash, 
    plan_hash, 
    action)
            
apg_plan_mgmt.validate_plans(
    action)
```

**返回值**

无效计划的数量。

**参数**


****  

| 参数 | 描述 | 
| --- | --- | 
| sql\$1hash | 计划的托管 SQL 语句的 sql\$1hash ID。 | 
| plan\$1hash | 托管计划的 plan\$1hash ID。使用 NULL 表示同一个 sql\$1hash ID 值的所有计划。 | 
| action |  函数为无效计划执行的操作。有效字符串值如下所示。大小写没有影响。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Optimize.Functions.html) 任何其他值作为空字符串处理。  | 

**使用说明**

使用格式 `validate_plans(action)` 来验证整个 `apg_plan_mgmt.dba_plans` 视图中，所有托管语句的所有托管计划。

使用格式 `validate_plans(sql_hash, plan_hash, action)`，为使用 `plan_hash` 指定的托管语句，验证以 `sql_hash` 指定的托管计划。

使用格式 `validate_plans(sql_hash, NULL, action)` 来验证使用 `sql_hash` 指定的托管语句的所有托管计划。

# Aurora PostgreSQL 兼容版的 apg\$1plan\$1mgmt.dba\$1plans 视图参考
<a name="AuroraPostgreSQL.Optimize.dba_plans_view_Reference"></a>

`apg_plan_mgmt.dba_plans` 视图中的计划信息列包括下列内容。


| dba\$1plans 列 | 描述 | 
| --- | --- | 
| cardinality\$1error |  对估计基数与实际基数之间错误的测量。*基数*是计划要处理的表行数。如果基数错误较大，则会增加计划并非最优的可能性。此列由 [apg\$1plan\$1mgmt.evolve\$1plan\$1baselines](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.evolve_plan_baselines) 函数填充。  | 
| compatibility\$1level |  此参数显示上次验证查询计划的时间。在 Aurora PostgreSQL 版本 12.19、13.15、14.12、15.7、16.3 及更高版本中，它显示 Aurora 版本号。对于较早的版本，它会显示功能特定的版本号。  将此参数值保持为其默认设置。Aurora PostgreSQL 会自动设置和更新此值。   | 
| created\$1by | 创建计划的已通过身份验证用户 (session\$1user)。 | 
| enabled |  计划已启用还是已禁用的指示符。默认情况下启用所有计划。您可以禁用计划以防止由优化程序使用。要修改此值，请使用 [apg\$1plan\$1mgmt.set\$1plan\$1enabled](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.set_plan_enabled) 函数。  | 
| environment\$1variables |  优化程序在捕获计划时覆盖的 PostgreSQL Grand Unified Configuration (GUC) 参数和值。  | 
| estimated\$1startup\$1cost | 在优化程序提供表行之前估算的优化程序设置成本。 | 
| estimated\$1total\$1cost | 估算的优化程序提供最终表行的成本。 | 
| execution\$1time\$1benefit\$1ms | 启用计划带来的执行时间效益，以毫秒为单位。此列由 [apg\$1plan\$1mgmt.evolve\$1plan\$1baselines](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.evolve_plan_baselines) 函数填充。 | 
| execution\$1time\$1ms | 计划将运行的估计时间，以毫秒为单位。此列由 [apg\$1plan\$1mgmt.evolve\$1plan\$1baselines](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.evolve_plan_baselines) 函数填充。 | 
| has\$1side\$1effects | 此值指示 SQL 语句是数据操作语言 (DML) 语句还是包含 VOLATILE 函数的 SELECT 语句。 | 
| last\$1used | 此值在计划执行或者计划是查询优化程序的最低成本计划时，更新为当前日期。此值存储在共享内存中，定期刷新到磁盘。要获取最新的值，请通过调用函数 apg\$1plan\$1mgmt.plan\$1last\$1used(sql\$1hash, plan\$1hash) 而不是读取 last\$1used 值，从共享内存中读取日期。有关其他信息，请参阅 [apg\$1plan\$1mgmt.plan\$1retention\$1period](AuroraPostgreSQL.Optimize.Parameters.md#AuroraPostgreSQL.Optimize.Parameters.plan_retention_period) 参数。 | 
| last\$1validated | 验证计划可以由 [apg\$1plan\$1mgmt.validate\$1plans](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.validate_plans) 函数或 [apg\$1plan\$1mgmt.evolve\$1plan\$1baselines](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.evolve_plan_baselines) 函数重新创建时的最近日期和时间。 | 
| last\$1verified | [apg\$1plan\$1mgmt.evolve\$1plan\$1baselines](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.evolve_plan_baselines) 函数验证计划是指定参数的最佳性能计划的最近日期和时间。 | 
| origin |  如何通过 [apg\$1plan\$1mgmt.capture\$1plan\$1baselines](AuroraPostgreSQL.Optimize.Parameters.md#AuroraPostgreSQL.Optimize.Parameters.capture_plan_baselines) 参数捕获的计划。包括下列有效值： `M` – 通过手动计划捕获来捕获的计划。 `A` – 通过自动计划捕获来捕获的计划。  | 
| param\$1list |  在语句是预编译语句时，传递到语句的参数值。  | 
| plan\$1created | 计划的创建日期和时间。 | 
| plan\$1hash | 计划标识符。plan\$1hash 和 sql\$1hash 的组合唯一标识特定计划。 | 
| plan\$1outline | 计划的表示，用于重新创建实际的执行计划，与数据库无关。树中的运算符对应于 EXPLAIN 输出中显示的运算符。 | 
| planning\$1time\$1ms |  运行计划程序的实际时间，以毫秒为单位。此列由 [apg\$1plan\$1mgmt.evolve\$1plan\$1baselines](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.evolve_plan_baselines) 函数填充。  | 
| queryId | 语句哈希，由 pg\$1stat\$1statements 扩展计算。这不是稳定或独立于数据库的标识符，因为它依赖于对象标识符 (OID)。捕获查询计划时，如果 compute\$1query\$1id 为 off，则该值将为 0。 | 
| sql\$1hash | SQL 语句文本的散列值，删除了文本以标准化。 | 
| sql\$1text | SQL 语句的完整文本。 | 
| status |  计划的状态，确定优化程序如何使用计划。包括下列有效值。 [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Optimize.dba_plans_view_Reference.html)  | 
| stmt\$1name | PREPARE 语句内 SQL 语句的名称。对于未命名的预编译语句，此值是为字符串。对于非预编译语句，此值是为 NULL。 | 
| total\$1time\$1benefit\$1ms |  启用此计划带来的总时间效益，以毫秒为单位。此值同时考虑到规划时间和执行时间。 如果此值为负数，则启用此计划有负面效果。此列由 [apg\$1plan\$1mgmt.evolve\$1plan\$1baselines](AuroraPostgreSQL.Optimize.Functions.md#AuroraPostgreSQL.Optimize.Functions.evolve_plan_baselines) 函数填充。  | 

# 查询计划管理高级功能
<a name="AuroraPostgreSQL.QPM.Advanced"></a>

以下是有关 Aurora PostgreSQL 查询计划管理（QPM）高级功能的信息：

**Topics**
+ [在副本中捕获 Aurora PostgreSQL 执行计划](AuroraPostgreSQL.QPM.Plancapturereplicas.md)
+ [支持表分区](AuroraPostgreSQL.QPM.Partitiontable.md)

# 在副本中捕获 Aurora PostgreSQL 执行计划
<a name="AuroraPostgreSQL.QPM.Plancapturereplicas"></a>

QPM（查询计划管理）允许您捕获由 Aurora 副本生成的查询计划并将其存储在 Aurora 数据库集群的主数据库实例上。您可以从所有 Aurora 副本中收集查询计划，并在主实例的中央永久表中维护一组最佳计划。然后，您可以在需要时将这些计划应用于其他副本。这将有助于您保持执行计划的稳定性，并跨数据库集群和引擎版本提高查询性能。

**Topics**
+ [先决条件](#AuroraPostgreSQL.QPM.Plancapturereplicas.Prereq)
+ [管理 Aurora 副本的计划捕获](#AuroraPostgreSQL.QPM.Plancapturereplicas.managing)
+ [故障排除](#AuroraPostgreSQL.QPM.Plancapturereplicas.Troubleshooting)

## 先决条件
<a name="AuroraPostgreSQL.QPM.Plancapturereplicas.Prereq"></a>

**在 Aurora 副本中开启 `capture_plan_baselines parameter`** - 将 `capture_plan_baselines` 参数设置为自动或手动在 Aurora 副本中捕获计划。有关更多信息，请参阅 [apg\$1plan\$1mgmt.capture\$1plan\$1baselines](AuroraPostgreSQL.Optimize.Parameters.md#AuroraPostgreSQL.Optimize.Parameters.capture_plan_baselines)。

**安装 postgres\$1fdw 扩展** - 必须安装 `postgres_fdw` 外部数据包装器扩展才能在 Aurora 副本中捕获计划。要安装扩展，请在每个数据库中运行以下命令。

```
postgres=> CREATE EXTENSION IF NOT EXISTS postgres_fdw;
```

## 管理 Aurora 副本的计划捕获
<a name="AuroraPostgreSQL.QPM.Plancapturereplicas.managing"></a>

**开启 Aurora 副本的计划捕获**  
您必须具有 `rds_superuser` 权限才能在 Aurora 副本中创建或删除计划捕获。有关用户角色和权限的更多信息，请参阅[了解 PostgreSQL 角色和权限](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Roles.html)。

要捕获计划，请在写入器数据库实例中调用 apg\$1plan\$1mgmt.create\$1replica\$1plan\$1capture 函数，如下所示：

```
postgres=> CALL apg_plan_mgmt.create_replica_plan_capture('endpoint', 'password');
```
+ 端点：Aurora Global Database 写入器端点或 cluster\$1endpoint 为 Aurora 副本中的计划捕获提供失效转移支持。

  有关 Aurora Global Database 写入器端点的更多信息，请参阅[查看 Amazon Aurora Global Database 的端点](aurora-global-database-connecting.md#viewing-endpoints)。

  有关集群端点的更多信息，请参阅 [Amazon Aurora 的集群端点](Aurora.Endpoints.Cluster.md)。
+ password - 我们建议您在创建密码时遵循以下准则以增强安全性：
  + 必须至少包含 8 个字符。
  + 必须包含至少一个大写字母、一个小写字母和一个数字。
  + 必须至少包含一个特殊字符（`?`、`!`、`#`、`<`、`>`、`*` 等等）。

**注意**  
如果您更改了端点、密码或端口号，则必须使用端点和密码再次运行 `apg_plan_mgmt.create_replica_plan_capture()`，才能重新初始化计划捕获。否则，从 Aurora 副本中捕获计划将失败。

**关闭 Aurora 副本的计划捕获**  
您可以通过在参数组中将 Aurora 副本中的参数 `capture_plan_baselines` 设置为 `off`，来将其关闭。

**删除 Aurora 副本的计划捕获**  
您可以在 Aurora 副本中完全删除计划捕获，但要确保在删除之前执行相关操作。要删除计划捕获，请调用 `apg_plan_mgmt.remove_replica_plan_capture`，如下所示：

```
postgres=> CALL apg_plan_mgmt.remove_replica_plan_capture();
```

您必须再次调用 apg\$1plan\$1mgmt.create\$1replica\$1plan\$1capture()，才能使用端点和密码在 Aurora 副本中开启计划捕获。

## 故障排除
<a name="AuroraPostgreSQL.QPM.Plancapturereplicas.Troubleshooting"></a>

下文介绍了 Aurora 副本中未按预期捕获计划的排查思路和解决方法。
+ **参数设置** - 检查 `capture_plan_baselines` 参数是否设置为正确的值以开启计划捕获。
+ **`postgres_fdw` 扩展已安装** - 使用以下查询来检查 `postgres_fdw` 是否已安装。

  ```
  postgres=> SELECT * FROM pg_extension WHERE extname = 'postgres_fdw'
  ```
+ **create\$1replica\$1plan\$1capture() 已调用** - 使用以下命令检查用户映射是否退出。否则，请调用 `create_replica_plan_capture()` 以初始化该功能。

  ```
  postgres=> SELECT * FROM pg_foreign_server WHERE srvname = 'apg_plan_mgmt_writer_foreign_server';
  ```
+ **集群端点和端口号**：检查端点和端口号是否合适。如果这些值不正确，则不会显示任何错误消息。

  使用以下命令验证是否在 create() 中使用了终端节点，并检查它位于哪个数据库中：

  ```
  postgres=> SELECT srvoptions FROM pg_foreign_server WHERE srvname = 'apg_plan_mgmt_writer_foreign_server';
  ```
+ **reload()** - 在 Aurora 副本中调用 apg\$1plan\$1mgmt.delete\$1plan() 之后，必须调用 apg\$1plan\$1mgmt.reload() 才能使删除函数生效。这将确保更改成功实施。
+ **Password** - 您必须按照上述准则在 create\$1replica\$1plan\$1capture() 中输入密码。否则，您将会收到错误消息。有关更多信息，请参阅[管理 Aurora 副本的计划捕获](#AuroraPostgreSQL.QPM.Plancapturereplicas.managing)。使用其他符合要求的密码。
+ **跨区域连接** - Aurora 全局数据库还支持 Aurora 副本中的计划捕获，其中写入器实例和 Aurora 副本可以位于不同的区域。确保在失效转移或切换事件发生后，使用 Aurora Global Database 写入器端点来保持连接。有关 Aurora Global Database 端点的更多信息，请参阅[查看 Amazon Aurora Global Database 的端点](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-global-database-connecting.html#viewing-endpoints)。写入器实例和跨区域副本必须能够使用 VPC 对等进行通信。有关更多信息，请参阅 [VPC 对等](https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html)。如果发生跨区域故障转移，则必须将终端节点重新配置为新的主数据库集群终端节点。
**注意**  
使用集群端点而不是 Aurora Global Database 写入器端点时，您将需要在执行全局失效转移或切换操作后更新集群端点。

# 支持表分区
<a name="AuroraPostgreSQL.QPM.Partitiontable"></a>

Aurora PostgreSQL 查询计划管理（QPM）在以下版本中支持声明式表分区：
+ 15.3 及更高的 15 版本
+ 14.8 及更高的 14 版本
+ 13.11 及更高的 13 版本

有关更多信息，请参阅[表分区](https://www.postgresql.org/docs/current/ddl-partitioning.html)。

**Topics**
+ [设置表分区](#AuroraPostgreSQL.QPM.Partitiontable.setup)
+ [捕获表分区的计划](#AuroraPostgreSQL.QPM.Partitiontable.capture)
+ [强制执行表分区计划](#AuroraPostgreSQL.QPM.Partitiontable.enforcement)
+ [命名约定](#AuroraPostgreSQL.QPM.Partitiontable.naming.convention)

## 设置表分区
<a name="AuroraPostgreSQL.QPM.Partitiontable.setup"></a>

 要在 Aurora PostgreSQL QPM 中设置表分区，请执行以下操作：

1. 在数据库集群参数组中将 `apg_plan_mgmt.plan_hash_version` 设置为 3 或更多。

1. 导航到使用查询计划管理且在 `apg_plan_mgmt.dba_plans` 视图中具有条目的数据库。

1. 调用 `apg_plan_mgmt.validate_plans('update_plan_hash')` 以更新 plans 表中的 `plan_hash` 值。

1. 对所有启用了查询计划管理且在 `apg_plan_mgmt.dba_plans` 视图中具有条目的数据库重复步骤 2-3。

有关这些参数的更多信息，请参阅[Aurora PostgreSQL 查询计划管理的参数参考](AuroraPostgreSQL.Optimize.Parameters.md)。

## 捕获表分区的计划
<a name="AuroraPostgreSQL.QPM.Partitiontable.capture"></a>

在 QPM 中，不同的计划以其 `plan_hash` 值来区分。要了解 `plan_hash` 如何变化，必须先了解类似的计划。

在 Append 节点级别累积的访问方法、去掉数字的索引名称和去掉数字的分区名称的组合必须是常量，才能将计划视为相同。在计划中访问的特定分区并不重要。在以下示例中，创建了一个包含 4 个分区的表 `tbl_a`。

```
postgres=>create table tbl_a(i int, j int, k int, l int, m int) partition by range(i);
CREATE TABLE
postgres=>create table tbl_a1 partition of tbl_a for values from (0) to (1000);
CREATE TABLE
postgres=>create table tbl_a2 partition of tbl_a for values from (1001) to (2000);
CREATE TABLE
postgres=>create table tbl_a3 partition of tbl_a for values from (2001) to (3000);
CREATE TABLE
postgres=>create table tbl_a4 partition of tbl_a for values from (3001) to (4000);
CREATE TABLE
postgres=>create index t_i on tbl_a using btree (i);
CREATE INDEX
postgres=>create index t_j on tbl_a using btree (j);
CREATE INDEX
postgres=>create index t_k on tbl_a using btree (k);
CREATE INDEX
```

以下计划被认为是相同的，因为无论查询查找的分区数量是多少，都使用单一扫描方法来扫描 `tbl_a`。

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 999 and j < 9910 and k > 50;
            
                        QUERY PLAN
-------------------------------------------------------------------
Seq Scan on tbl_a1 tbl_a
    Filter: ((i >= 990) AND (i <= 999) AND (j < 9910) AND (k > 50))
SQL Hash: 1553185667, Plan Hash: -694232056
(3 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50;
            
                        QUERY PLAN
-------------------------------------------------------------------
Append
    ->  Seq Scan on tbl_a1 tbl_a_1
            Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
    ->  Seq Scan on tbl_a2 tbl_a_2
            Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
    SQL Hash: 1553185667, Plan Hash: -694232056
    (6 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50;
            
                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Seq Scan on tbl_a1 tbl_a_1
         Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a3 tbl_a_3
         Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
 SQL Hash: 1553185667, Plan Hash: -694232056
(8 rows)
```

以下 3 个计划也被认为是相同的，因为在父级别，访问方法、去除数字的索引名称和去除数字的分区名称是 `SeqScan tbl_a`、`IndexScan (i_idx) tbl_a`。

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50;
            
                                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Seq Scan on tbl_a1 tbl_a_1
         Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a2_i_idx on tbl_a2 tbl_a_2
         Index Cond: ((i >= 990) AND (i <= 1100))
         Filter: ((j < 9910) AND (k > 50))
 SQL Hash: 1553185667, Plan Hash: -993736942
(7 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50;
            
                                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 2100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a3_i_idx on tbl_a3 tbl_a_3
         Index Cond: ((i >= 990) AND (i <= 2100))
         Filter: ((j < 9910) AND (k > 50))
 SQL Hash: 1553185667, Plan Hash: -993736942
(10 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 3100 and j < 9910 and k > 50;
            
                                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Seq Scan on tbl_a1 tbl_a_1
         Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a3 tbl_a_3
         Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a4_i_idx on tbl_a4 tbl_a_4
         Index Cond: ((i >= 990) AND (i <= 3100))
         Filter: ((j < 9910) AND (k > 50))
 SQL Hash: 1553185667, Plan Hash: -993736942
(11 rows)
```

无论子分区中出现顺序和次数有何不同，在上述每种计划的父级别，访问方法、去除数字的索引名称和去除数字的分区名称都是常量。

但是，如果满足以下任何条件，则计划将被视为不同：
+ 计划中使用了任何其他访问方法。

  ```
  postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50;
                      
                                  QUERY PLAN
  --------------------------------------------------------------------------
   Append
     ->  Seq Scan on tbl_a1 tbl_a_1
           Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
     ->  Seq Scan on tbl_a2 tbl_a_2
           Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
     ->  Bitmap Heap Scan on tbl_a3 tbl_a_3
           Recheck Cond: ((i >= 990) AND (i <= 2100))
           Filter: ((j < 9910) AND (k > 50))
           ->  Bitmap Index Scan on tbl_a3_i_idx
                 Index Cond: ((i >= 990) AND (i <= 2100))
   SQL Hash: 1553185667, Plan Hash: 1134525070
  (11 rows)
  ```
+ 计划中有任何访问方法不再使用。

  ```
  postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50;
                      
                                 QUERY PLAN
  --------------------------------------------------------------------------
   Append
     ->  Seq Scan on tbl_a1 tbl_a_1
           Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
     ->  Seq Scan on tbl_a2 tbl_a_2
           Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
   SQL Hash: 1553185667, Plan Hash: -694232056
  (6 rows)
  ```
+ 与索引方法关联的索引已更改。

  ```
  postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50;
                      
                               QUERY PLAN
  --------------------------------------------------------------------------
   Append
     ->  Seq Scan on tbl_a1 tbl_a_1
           Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
     ->  Index Scan using tbl_a2_j_idx on tbl_a2 tbl_a_2
           Index Cond: (j < 9910)
           Filter: ((i >= 990) AND (i <= 1100) AND (k > 50))
   SQL Hash: 1553185667, Plan Hash: -993343726
  (7 rows)
  ```

## 强制执行表分区计划
<a name="AuroraPostgreSQL.QPM.Partitiontable.enforcement"></a>

已批准的分区表计划通过位置对应关系来强制执行。这些计划并不特定于分区，可以在原始查询中引用的计划以外的分区上强制执行。对于访问的分区数量与原始批准的概况数量不同的查询，也可以强制执行计划。

例如，如果批准的概况适用于以下计划：

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50;
            
                                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 2100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a3_i_idx on tbl_a3 tbl_a_3
         Index Cond: ((i >= 990) AND (i <= 2100))
         Filter: ((j < 9910) AND (k > 50))   
 SQL Hash: 1553185667, Plan Hash: -993736942
(10 rows)
```

则也可以在引用 2 个、4 个或更多分区的 SQL 查询上强制执行此计划。对于 2 个和 4 个分区访问，这些场景可能会产生以下可能的计划：

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1100 and j < 9910 and k > 50;
            
                                QUERY PLAN
----------------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 1100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 1100) AND (j < 9910) AND (k > 50))
 Note: An Approved plan was used instead of the minimum cost plan. 
 SQL Hash: 1553185667, Plan Hash: -993736942, Minimum Cost Plan Hash: -1873216041
(8 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 3100 and j < 9910 and k > 50;
            
                                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 3100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a3_i_idx on tbl_a3 tbl_a_3
         Index Cond: ((i >= 990) AND (i <= 3100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a4 tbl_a_4
         Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50))
 Note: An Approved plan was used instead of the minimum cost plan.
 SQL Hash: 1553185667, Plan Hash: -993736942, Minimum Cost Plan Hash: -1873216041 
(12 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 3100 and j < 9910 and k > 50;
            
                                QUERY PLAN
----------------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 3100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 3100) AND (j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a3_i_idx on tbl_a3 tbl_a_3
         Index Cond: ((i >= 990) AND (i <= 3100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Index Scan using tbl_a4_i_idx on tbl_a4 tbl_a_4
         Index Cond: ((i >= 990) AND (i <= 3100))
         Filter: ((j < 9910) AND (k > 50))
 Note: An Approved plan was used instead of the minimum cost plan.
 SQL Hash: 1553185667, Plan Hash: -993736942, Minimum Cost Plan Hash: -1873216041
(14 rows)
```

考虑另一项已批准的计划，每个分区使用不同的访问方法：

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 2100 and j < 9910 and k > 50;
            
                                QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 2100))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 2100) AND (j < 9910) AND (k > 50))
   ->  Bitmap Heap Scan on tbl_a3 tbl_a_3
         Recheck Cond: ((i >= 990) AND (i <= 2100))
         Filter: ((j < 9910) AND (k > 50))
         ->  Bitmap Index Scan on tbl_a3_i_idx
               Index Cond: ((i >= 990) AND (i <= 2100))
 SQL Hash: 1553185667, Plan Hash: 2032136998
(12 rows)
```

在这种情况下，任何从两个分区进行读取的计划都将无法强制执行。除非批准的计划中的所有（访问方法、索引名称）组合都可用，否则该计划将无法强制执行。例如，以下计划具有不同的计划哈希值，在这些情况下无法强制执行批准的计划：

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1900 and j < 9910 and k > 50;
            
                              QUERY PLAN
-------------------------------------------------------------------------
 Append
   ->  Bitmap Heap Scan on tbl_a1 tbl_a_1
         Recheck Cond: ((i >= 990) AND (i <= 1900))
         Filter: ((j < 9910) AND (k > 50))
         ->  Bitmap Index Scan on tbl_a1_i_idx
               Index Cond: ((i >= 990) AND (i <= 1900))
   ->  Bitmap Heap Scan on tbl_a2 tbl_a_2
         Recheck Cond: ((i >= 990) AND (i <= 1900))
         Filter: ((j < 9910) AND (k > 50))
         ->  Bitmap Index Scan on tbl_a2_i_idx
               Index Cond: ((i >= 990) AND (i <= 1900))
  Note: This is not an Approved plan.  No usable Approved plan was found.
  SQL Hash: 1553185667, Plan Hash: -568647260
(13 rows)
```

```
postgres=>explain (hashes true, costs false) select j, k from tbl_a where i between 990 and 1900 and j < 9910 and k > 50;
            
                              QUERY PLAN
--------------------------------------------------------------------------
 Append
   ->  Index Scan using tbl_a1_i_idx on tbl_a1 tbl_a_1
         Index Cond: ((i >= 990) AND (i <= 1900))
         Filter: ((j < 9910) AND (k > 50))
   ->  Seq Scan on tbl_a2 tbl_a_2
         Filter: ((i >= 990) AND (i <= 1900) AND (j < 9910) AND (k > 50))
 Note: This is not an Approved plan.  No usable Approved plan was found.
 SQL Hash: 1553185667, Plan Hash: -496793743
(8 rows)
```

## 命名约定
<a name="AuroraPostgreSQL.QPM.Partitiontable.naming.convention"></a>

为了让 QPM 强制执行声明式分区表计划，必须遵循父表、表分区和索引的特定命名规则：
+ **父表名称** – 这些名称在字母或特殊字符方面必须有所不同，而不仅仅是数字方面的不同。例如，tA、tB 和 tC 是单独父表的可接受名称，而 t1、t2 和 t3 不是。
+ **单个分区表名称** – 同一父表的分区表之间应只存在数字方面的不同。例如，tA 的可接受分区名称可以是 tA1、tA2 或 t1A、t2A 甚至多位数。

  任何其他差异（字母、特殊字符）均不能保证计划强制执行。
+ **索引名称** – 在分区表层次结构中，请确保所有索引都具有唯一的名称。这意味着名称的非数字部分必须不同。例如，如果您有一个名为 `tA` 的分区表，其索引名称为 `tA_col1_idx1`，则不能再将其他索引命名为 `tA_col1_idx2`。但是，您可以具有名为 `tA_a_col1_idx2` 的索引，因为名称的非数字部分是唯一的。此规则适用于在父表和单个分区表上创建的索引。

 不遵守上述命名约定可能会导致批准的计划无法强制执行。以下示例说明了这种无法强制执行的情况：

```
postgres=>create table t1(i int, j int, k int, l int, m int) partition by range(i);
CREATE TABLE
postgres=>create table t1a partition of t1 for values from (0) to (1000);
CREATE TABLE
postgres=>create table t1b partition of t1 for values from (1001) to (2000);
CREATE TABLE
postgres=>SET apg_plan_mgmt.capture_plan_baselines TO 'manual';
SET
postgres=>explain (hashes true, costs false) select count(*) from t1 where i > 0;

                            QUERY PLAN
--------------------------------------------------------------------------
 Aggregate
   ->  Append
         ->  Seq Scan on t1a t1_1
               Filter: (i > 0)
         ->  Seq Scan on t1b t1_2
               Filter: (i > 0)
 SQL Hash: -1720232281, Plan Hash: -1010664377
(7 rows)
```

```
postgres=>SET apg_plan_mgmt.use_plan_baselines TO 'on';
SET
postgres=>explain (hashes true, costs false) select count(*) from t1 where i > 1000;

                            QUERY PLAN
-------------------------------------------------------------------------
 Aggregate
   ->  Seq Scan on t1b t1
         Filter: (i > 1000)
 Note: This is not an Approved plan. No usable Approved plan was found.
 SQL Hash: -1720232281, Plan Hash: 335531806
(5 rows)
```

尽管这两个计划可能看起来相同，但由于子表的名称，它们的 `Plan Hash` 值有所不同。表名称因字母字符而异，而不仅仅是导致执行失败的数字。