

# 排除 Amazon Aurora MySQL 数据库性能故障
<a name="aurora-mysql-troubleshooting"></a>

本主题重点介绍一些常见的 Aurora MySQL 数据库性能问题，以及如何进行故障排除或收集信息来快速修复这些问题。我们将数据库性能分为两类：
+ 服务器性能 - 整个数据库服务器的运行速度较慢。
+ 查询性能 - 一个或多个查询的运行时间较长。

## AWS 监控选项
<a name="aurora-mysql-troubleshooting.monitoring"></a>

我们建议您使用以下 AWS 监控选项来协助进行故障排除：
+ Amazon CloudWatch – Amazon CloudWatch 实时监控 AWS 资源以及在 AWS 上运行的应用程序。您可以使用 CloudWatch 收集和跟踪指标，这些指标是您可以针对资源和应用程序衡量的变量。有关更多信息，请参阅 [What is Amazon CloudWatch?](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html)

  您可以在 AWS 管理控制台上查看数据库实例的所有系统指标和过程信息。您可以配置 Aurora MySQL 数据库集群以将一般、慢速、审核和错误日志数据发布到 Amazon CloudWatch Logs 中的日志组。这样，您就可以查看趋势，在主机受到影响时维护日志，并创建“正常”性能的基准来轻松地识别异常或变化。有关更多信息，请参阅 [将 Amazon Aurora MySQL 日志发布到 Amazon CloudWatch Logs](AuroraMySQL.Integrating.CloudWatch.md)。
+ 增强监控 – 要为 Aurora MySQL 数据库启用其它 Amazon CloudWatch 指标，请开启增强监控。创建或修改 Aurora 数据库集群时，请选择**启用增强监控**。这样，Aurora 就可以向 CloudWatch 发布性能指标。可用的一些关键指标包括 CPU 使用率、数据库连接、存储使用情况和查询延迟。这些指标有助于确定性能瓶颈。

  为数据库实例传输的信息量与为增强监控功能定义的粒度成正比。监控间隔越短，操作系统指标报告频率越高，监控成本也就越高。要管理成本，请为您的 AWS 账户中的不同实例设置不同的粒度。创建实例时的默认粒度为 60 秒。有关更多信息，请参阅 [增强监测的成本](USER_Monitoring.OS.md#USER_Monitoring.OS.cost)。
+ Performance Insights – 您可以查看所有数据库调用指标。这包括数据库锁定、等待和已处理的行数，所有这些都可用于进行故障排除。创建或修改 Aurora 数据库集群时，请选择**开启 Performance Insights**。默认情况下，Performance Insights 的数据留存期为 7 天，但可以对其进行自定义来分析长期性能趋势。如果留存期超过 7 天，则需要升级到付费套餐。有关更多信息，请参阅 [Performance Insights 定价](https://aws.amazon.com/rds/performance-insights/pricing/)。您可以分别为每个 Aurora 数据库实例设置数据留存期。有关更多信息，请参阅 [在 Amazon Aurora 上使用性能详情监控数据库负载](USER_PerfInsights.md)。

## 出现 Aurora MySQL 数据库性能问题的最常见原因
<a name="aurora-mysql-troubleshooting-common"></a>

您可以使用以下步骤来解决 Aurora MySQL 数据库中的性能问题。我们按调查的逻辑顺序列出了这些步骤，但它们并不是线性的。一项发现可能跨越多个步骤，从而形成一系列调查路径。

1. [工作负载](aurora-mysql-troubleshooting-workload.md) – 了解您的数据库工作负载。

1. [日志记录](aurora-mysql-troubleshooting-logging.md) – 查看所有数据库日志。

1. [数据库连接](mysql-troubleshooting-dbconn.md) – 确保应用程序与数据库之间的连接可靠。

1. [查询性能](aurora-mysql-troubleshooting-query.md) – 检查您的查询执行计划，查看它们是否已更改。代码更改可能会导致计划发生变化。

# 排查 Aurora MySQL 数据库的工作负载问题
<a name="aurora-mysql-troubleshooting-workload"></a>

数据库工作负载可以看作是读取和写入。了解“正常”数据库工作负载后，您可以调整查询和数据库服务器，来满足不断变化的需求。性能可能发生变化的原因有很多，因此第一步是了解发生了什么变化。
+ 是否进行了主要版本或次要版本升级？

  主要版本升级包括对引擎代码的更改，尤其是优化器中的更改，这些更改可能会更改查询执行计划。升级数据库版本，尤其是主要版本时，分析数据库工作负载并相应进行调整非常重要。调整可能包括优化和重写查询，或者添加和更新参数设置，具体取决于测试的结果。了解造成影响的原因将使您能够开始专注于该特定区域。

  有关更多信息，请参阅 MySQL 文档中的 [What is new in MySQL 8.0](https://dev.mysql.com/doc/refman/8.0/en/mysql-nutshell.html) 和 [Server and status variables and options added, deprecated, or removed in MySQL 8.0](https://dev.mysql.com/doc/refman/8.0/en/added-deprecated-removed.html)，以及[比较 Aurora MySQL 版本 2 和 Aurora MySQL 版本 3](AuroraMySQL.Compare-v2-v3.md)。
+ 正在处理的数据（行计数）是否有所增加？
+ 是否有更多查询并行运行？
+ 模式或数据库是否发生变化？
+ 是否存在代码缺陷或修复？

**Contents**
+ [

## 实例主机指标
](#ams-workload-instance)
  + [

### CPU 使用率
](#ams-workload-cpu)
  + [

### 内存使用量
](#ams-workload-instance-memory)
  + [

### 网络吞吐量
](#ams-workload-network)
+ [

## 数据库指标
](#ams-workload-db)
+ [

# 排查 Aurora MySQL 数据库的内存使用问题
](ams-workload-memory.md)
  + [

## 示例 1：持续的高内存使用量
](ams-workload-memory.md#ams-workload-memory.example1)
  + [

## 示例 2：短暂内存峰值
](ams-workload-memory.md#ams-workload-memory.example2)
  + [

## 示例 3：可释放内存持续下降且无法回收
](ams-workload-memory.md#ams-workload-memory.example3)
+ [

# 排查 Aurora MySQL 数据库内存不足问题
](AuroraMySQLOOM.md)

## 实例主机指标
<a name="ams-workload-instance"></a>

监控 CPU、内存和网络活动等实例主机指标，来协助了解工作负载是否发生了变化。了解工作负载变化有两个主要概念：
+ 利用率 - 设备（例如 CPU 或磁盘）的使用情况。它可以是基于时间的，也可以是基于容量的。
  + 基于时间 - 资源在特定观察期内忙碌的时间量。
  + 基于容量 – 系统或组件可以提供的吞吐量，以其容量的百分比表示。
+ 饱和度 - 资源需要的工作量超过其处理能力的程度。当基于容量的使用率达到 100% 时，将无法处理额外的工作，必须排队。

### CPU 使用率
<a name="ams-workload-cpu"></a>

您可以使用以下工具来确定 CPU 使用率和饱和度：
+ CloudWatch 提供了 `CPUUtilization` 指标。如果该指标达到 100%，则实例饱和。但是，CloudWatch 指标按 1 分钟取平均值，因而粒度不足。

  有关 CloudWatch 指标的更多信息，请参阅[Amazon Aurora 的实例级指标](Aurora.AuroraMonitoring.Metrics.md#Aurora.AuroraMySQL.Monitoring.Metrics.instances)。
+ 增强监控提供由操作系统 `top` 命令返回的指标。它以 1 秒的粒度显示平均负载和以下 CPU 状态：
  + `Idle (%)` = 空闲时间
  + `IRQ (%)` = 软件中断
  + `Nice (%)` = 对于优先级为 [niced](https://en.wikipedia.org/wiki/Nice_(Unix)) 的进程，状态为 Nice 的时间。
  + `Steal (%)` = 为其他租户提供服务所花费的时间（与虚拟化相关）
  + `System (%)` = 系统时间
  + `User (%)` = 用户时间
  + `Wait (%)` = I/O 等待

  有关增强监控指标的更多信息，请参阅 [Aurora 的操作系统指标](USER_Monitoring-Available-OS-Metrics.md#USER_Monitoring-Available-OS-Metrics-RDS)。

### 内存使用量
<a name="ams-workload-instance-memory"></a>

如果系统面临内存压力，并且资源消耗达到饱和，则应观察到高程度的页面扫描、分页、交换和内存不足错误。

您可以使用以下工具来确定内存使用量和饱和度：

CloudWatch 提供了 `FreeableMemory` 指标，该指标显示通过刷新部分操作系统缓存和当前可用内存可以回收多少内存。

有关 CloudWatch 指标的更多信息，请参阅[Amazon Aurora 的实例级指标](Aurora.AuroraMonitoring.Metrics.md#Aurora.AuroraMySQL.Monitoring.Metrics.instances)。

增强监控提供以下指标，有助于您识别内存使用量问题：
+ `Buffers (KB)` – 在写入存储设备前用于缓冲 I/O 请求的内存量（以 KB 为单位）。
+ `Cached (KB)` – 用于缓存基于文件系统的 I/O 的内存量。
+ `Free (KB)` – 未分配的内存量（以 KB 为单位）。
+ `Swap` –“已缓存”、“可用”和“总计”。

例如，如果您看到您的数据库实例使用 `Swap` 内存，则您的工作负载的内存总量将大于您的实例当前可用的内存量。我们建议增加数据库实例的大小或调整工作负载来使用更少的内存。

有关增强监控指标的更多信息，请参阅 [Aurora 的操作系统指标](USER_Monitoring-Available-OS-Metrics.md#USER_Monitoring-Available-OS-Metrics-RDS)。

有关使用性能架构和 `sys` 架构来确定哪些连接和组件正在使用内存的更多详细信息，请参阅 [排查 Aurora MySQL 数据库的内存使用问题](ams-workload-memory.md)。

### 网络吞吐量
<a name="ams-workload-network"></a>

CloudWatch 提供以下网络总吞吐量指标，所有指标均按 1 分钟取平均值：
+ `NetworkReceiveThroughput` – Aurora 数据库集群中每个实例从客户端接收的网络吞吐量。
+ `NetworkTransmitThroughput` – Aurora 数据库集群中每个实例发送到客户端的网络吞吐量。
+ `NetworkThroughput` – Aurora 数据库集群中每个实例从客户端接收和发送到客户端的网络吞吐量。
+ `StorageNetworkReceiveThroughput` – 数据库集群中每个实例从 Aurora 存储子系统接收的网络吞吐量。
+ `StorageNetworkTransmitThroughput` – Aurora 数据库集群中每个实例发送到 Aurora 存储子系统的网络吞吐量。
+ `StorageNetworkThroughput` – Aurora 数据库集群中每个实例从 Aurora 存储子系统接收与发送到该子系统的网络吞吐量。

有关 CloudWatch 指标的更多信息，请参阅[Amazon Aurora 的实例级指标](Aurora.AuroraMonitoring.Metrics.md#Aurora.AuroraMySQL.Monitoring.Metrics.instances)。

增强监控提供 `network` 已接收（**RX**）和已发送（**TX**）图表，粒度高达 1 秒。

有关增强监控指标的更多信息，请参阅 [Aurora 的操作系统指标](USER_Monitoring-Available-OS-Metrics.md#USER_Monitoring-Available-OS-Metrics-RDS)。

## 数据库指标
<a name="ams-workload-db"></a>

检查以下 CloudWatch 指标，来了解工作负载变化：
+ `BlockedTransactions` – 每秒内数据库中被阻止的事务的平均数。
+ `BufferCacheHitRatio` – 缓冲区缓存提供服务的请求的百分比。
+ `CommitThroughput` – 每秒平均提交操作数量。
+ `DatabaseConnections` – 连接至数据库实例的客户端网络连接数。
+ `Deadlocks` – 每秒内数据库中死锁的平均数。
+ `DMLThroughput` – 每秒平均插入、更新和删除数。
+ `ResultSetCacheHitRatio` – 查询缓存提供服务的请求的百分比。
+ `RollbackSegmentHistoryListLength` – 记录已提交事务（带有删除标记的记录）的撤销日志。
+ `RowLockTime` – 为 InnoDB 表获取行锁定所花的总时间。
+ `SelectThroughput` – 每秒平均选择查询数。

有关 CloudWatch 指标的更多信息，请参阅[Amazon Aurora 的实例级指标](Aurora.AuroraMonitoring.Metrics.md#Aurora.AuroraMySQL.Monitoring.Metrics.instances)。

检查工作负载时，请考虑以下问题：

1. 数据库实例类最近是否发生了变化，例如，将实例大小从 8xlarge 缩小到 4xlarge，或者从 db.r5 更改为 db.r6？ 

1. 您能否创建一个克隆并重现此问题，或者该问题只发生在那一个实例上？

1. 是否存在服务器资源耗尽、CPU 过高或内存耗尽的问题？ 如果是，则这可能意味着需要额外的硬件。

1. 一个或多个查询是否需要更长的时间？

1. 这些更改是否由升级（尤其是主要版本升级）引起？ 如果是，则比较升级前和升级后的指标。

1. 读取器数据库实例的数量是否发生了变化？

1. 您是否启用了常规、审计或二进制日志记录？ 有关更多信息，请参阅 [Aurora MySQL 数据库日志记录](aurora-mysql-troubleshooting-logging.md)。

1. 您是否启用、禁用或更改了对二进制日志（binlog）复制的使用？

1. 是否存在任何持有大量行锁的长期运行的事务？ 检查 InnoDB 历史记录列表长度（HLL），来获取长时间运行的事务的指示。

   有关更多信息，请参阅[InnoDB 历史记录列表长度显著增加](proactive-insights.history-list.md)和博客文章 [Why is my SELECT query running slowly on my Amazon Aurora MySQL DB cluster?](https://repost.aws/knowledge-center/aurora-mysql-slow-select-query)

   1. 如果写入事务导致 HLL 较大，则表示 `UNDO` 日志正在累积（未定期清理）。在大型写入事务中，这种累积可能会迅速增长。在 MySQL 中，`UNDO` 存储在 [SYSTEM 表空间](https://dev.mysql.com/doc/refman/5.7/en/innodb-system-tablespace.html)中。`SYSTEM` 表空间不可收缩。`UNDO` 日志可能会导致 `SYSTEM` 表空间增长到若干 GB，甚至 TB。清除后，通过对数据进行逻辑备份（转储）来释放分配的空间，然后将转储导入到新的数据库实例。

   1. 如果较大的 HLL 是由读取事务（长时间运行的查询）引起的，则可能意味着该查询使用了大量的临时空间。通过重启来释放临时空间。检查 Performance Insights 数据库指标，来了解 `Temp` 部分（例如 `created_tmp_tables`）是否有任何变化。有关更多信息，请参阅 [在 Amazon Aurora 上使用性能详情监控数据库负载](USER_PerfInsights.md)。

1. 能否将长时间运行的事务拆分为修改较少行的较小事务？

1. 被阻止的事务是否有任何变化或死锁是否增加？ 检查 Performance Insights 数据库指标，来了解 `Locks` 部分中的状态变量（例如 `innodb_row_lock_time`、` innodb_row_lock_waits` 和 ` innodb_dead_locks`）是否有任何变化。使用 1 分钟或 5 分钟间隔。

1. 等待事件是否增加？ 以 1 分钟或 5 分钟间隔检查 Performance Insights 等待事件和等待类型。分析排名靠前的等待事件，看看它们是否与工作负载变化或数据库争用相关。例如，`buf_pool mutex` 表示缓冲池争用。有关更多信息，请参阅 [使用等待事件优化 Aurora MySQL](AuroraMySQL.Managing.Tuning.wait-events.md)。

# 排查 Aurora MySQL 数据库的内存使用问题
<a name="ams-workload-memory"></a>

虽然 CloudWatch、增强监控和性能详情可以很好地概述操作系统级别的内存使用情况，例如数据库进程使用了多少内存，但它们不允许您细分引擎中的哪些连接或组件可能导致这种内存使用。

要对此进行故障排除，您可以使用 Performance Schema 和 `sys` 架构。在 Aurora MySQL 版本 3 中，当启用 Performance Schema 时，默认情况下会启用内存检测。在 Aurora MySQL 版本 2 中，默认情况下，仅对 Performance Schema 内存使用情况启用内存检测。有关 Performance Schema 中可用于跟踪内存使用情况和启用 Performance Schema 内存检测的表的信息，请参阅 MySQL 文档中的 [Memory summary tables](https://dev.mysql.com/doc/refman/8.3/en/performance-schema-memory-summary-tables.html)。有关将 Performance Schema 与性能详情结合使用的更多信息，请参阅[Aurora MySQL 上性能详情的性能架构概述](USER_PerfInsights.EnableMySQL.md)。

虽然 Performance Schema 中提供了用于跟踪当前内存使用情况的详细信息，但 MySQL [sys schema](https://dev.mysql.com/doc/refman/8.0/en/sys-schema.html) 在 Performance Schema 表之上具有视图，您可以使用这些视图来快速查明使用内存的位置。

在 `sys` 架构中，可以使用以下视图，按连接、组件和查询来跟踪内存使用情况。


| 视图 | 描述 | 
| --- | --- | 
|  [memory\$1by\$1host\$1by\$1current\$1bytes](https://dev.mysql.com/doc/refman/8.0/en/sys-memory-by-host-by-current-bytes.html)  |  按主机提供有关引擎内存使用情况的信息。这对于识别哪些应用程序服务器或客户端主机正在消耗内存很有用。  | 
|  [memory\$1by\$1thread\$1by\$1current\$1bytes](https://dev.mysql.com/doc/refman/8.0/en/sys-memory-by-thread-by-current-bytes.html)  |  按线程 ID 提供有关引擎内存使用情况的信息。MySQL 中的线程 ID 可以是客户端连接或后台线程。您可以使用 [sys.processlist](https://dev.mysql.com/doc/refman/8.0/en/sys-processlist.html) 视图或 [performance\$1schema.threads](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-threads-table.html) 表将线程 ID 映射到 MySQL 连接 ID。  | 
|  [memory\$1by\$1user\$1by\$1current\$1bytes](https://dev.mysql.com/doc/refman/8.0/en/sys-memory-by-user-by-current-bytes.html)  |  按用户提供有关引擎内存使用情况的信息。这对于识别哪些用户账户或客户端正在消耗内存很有用。  | 
|  [memory\$1global\$1by\$1current\$1bytes](https://dev.mysql.com/doc/refman/8.0/en/sys-memory-global-by-current-bytes.html)  |  按引擎组件提供有关引擎内存使用情况的信息。这对于按引擎缓冲区或组件全局识别内存使用情况很有用。例如，您可能会看到 InnoDB 缓冲池的 `memory/innodb/buf_buf_pool` 事件，或者预处理语句的 `memory/sql/Prepared_statement::main_mem_root` 事件。  | 
|  [memory\$1global\$1total](https://dev.mysql.com/doc/refman/8.0/en/sys-memory-global-total.html)  |  概述数据库引擎中跟踪的内存使用总量。  | 

在 Aurora MySQL 版本 3.05 及更高版本中，您还可以在 [Performance Schema statement summary tables](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-statement-summary-tables.html) 中按语句摘要跟踪最大内存使用量。语句摘要表包含标准化语句摘要及有关其执行情况的汇总统计数据。`MAX_TOTAL_MEMORY` 列可以帮助您确定自上次重置统计数据以来或自重启数据库实例以来，查询摘要所使用的最大内存。这对于识别可能消耗大量内存的特定查询很有用。

**注意**  
 Performance Schema 和 `sys` 架构显示服务器上的当前内存使用情况，以及每个连接和引擎组件消耗的内存的历史最高水平。由于 Performance Schema 在内存中维护，因此数据库实例重启时会重置信息。为了保持一段时间内的历史记录，建议您在 Performance Schema 之外配置此数据的检索和存储。

**Topics**
+ [

## 示例 1：持续的高内存使用量
](#ams-workload-memory.example1)
+ [

## 示例 2：短暂内存峰值
](#ams-workload-memory.example2)
+ [

## 示例 3：可释放内存持续下降且无法回收
](#ams-workload-memory.example3)

## 示例 1：持续的高内存使用量
<a name="ams-workload-memory.example1"></a>

在 CloudWatch 中全局观察 `FreeableMemory`，我们可以看到，在 2024 年 3 月 26 日凌晨 2:59（UTC 时间），内存使用量大幅增加。

![\[FreeableMemory 图显示了较高的内存使用量。\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/images/ams-freeable-memory.png)


这并不能告诉我们全貌。要确定哪个组件使用的内存最多，您可以登录数据库并查看 `sys.memory_global_by_current_bytes`。此表包含 MySQL 跟踪的内存事件列表，以及有关每个事件的内存分配的信息。每个内存跟踪事件都以 `memory/%` 开头，后跟与该事件关联的引擎组件/功能的其它信息。

例如，`memory/performance_schema/%` 用于与 Performance Schema 相关的内存事件，`memory/innodb/%` 用于 InnoDB，等等。有关事件命名约定的更多信息，请参阅 MySQL 文档中的 [Performance Schema instrument naming conventions](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-instrument-naming.html)。

从以下查询中，我们可以根据 `current_alloc` 找到可能的罪魁祸首，但我们也可能看到许多 `memory/performance_schema/%` 事件。

```
mysql> SELECT * FROM sys.memory_global_by_current_bytes LIMIT 10;

+-----------------------------------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| event_name                                                                  | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc |
+-----------------------------------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| memory/sql/Prepared_statement::main_mem_root                                |        512817 | 4.91 GiB      | 10.04 KiB         |     512823 | 4.91 GiB   | 10.04 KiB      |
| memory/performance_schema/prepared_statements_instances                     |           252 | 488.25 MiB    | 1.94 MiB          |        252 | 488.25 MiB | 1.94 MiB       |
| memory/innodb/hash0hash                                                     |             4 | 79.07 MiB     | 19.77 MiB         |          4 | 79.07 MiB  | 19.77 MiB      |
| memory/performance_schema/events_errors_summary_by_thread_by_error          |          1028 | 52.27 MiB     | 52.06 KiB         |       1028 | 52.27 MiB  | 52.06 KiB      |
| memory/performance_schema/events_statements_summary_by_thread_by_event_name |             4 | 47.25 MiB     | 11.81 MiB         |          4 | 47.25 MiB  | 11.81 MiB      |
| memory/performance_schema/events_statements_summary_by_digest               |             1 | 40.28 MiB     | 40.28 MiB         |          1 | 40.28 MiB  | 40.28 MiB      |
| memory/performance_schema/memory_summary_by_thread_by_event_name            |             4 | 31.64 MiB     | 7.91 MiB          |          4 | 31.64 MiB  | 7.91 MiB       |
| memory/innodb/memory                                                        |         15227 | 27.44 MiB     | 1.85 KiB          |      20619 | 33.33 MiB  | 1.66 KiB       |
| memory/sql/String::value                                                    |         74411 | 21.85 MiB     |  307 bytes        |      76867 | 25.54 MiB  |  348 bytes     |
| memory/sql/TABLE                                                            |          8381 | 21.03 MiB     | 2.57 KiB          |       8381 | 21.03 MiB  | 2.57 KiB       |
+-----------------------------------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
10 rows in set (0.02 sec)
```

我们之前提到过， Performance Schema 存储在内存中，这意味着在 `performance_schema` 内存检测中也会对它进行跟踪。

**注意**  
如果您发现 Performance Schema 使用了大量内存，并且想要限制其内存使用量，则可以根据需要调整数据库参数。有关更多信息，请参阅 MySQL 文档中的 [The Performance Schema memory-allocation model](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-memory-model.html)。

为了便于阅读，您可以重新运行相同的查询，但排除 Performance Schema 事件。输出显示以下内容：
+ 主要的内存消耗者是 `memory/sql/Prepared_statement::main_mem_root`。
+ `current_alloc` 列告诉我们，MySQL 当前为此事件分配了 4.91 GiB。
+ `high_alloc column` 告诉我们，4.91 GiB 是自上次重置统计数据或服务器重启以来 `current_alloc` 的历史最高水平。这意味着 `memory/sql/Prepared_statement::main_mem_root` 已达到其最高值。

```
mysql> SELECT * FROM sys.memory_global_by_current_bytes WHERE event_name NOT LIKE 'memory/performance_schema/%' LIMIT 10;

+-----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| event_name                                    | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc |
+-----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| memory/sql/Prepared_statement::main_mem_root  |        512817 | 4.91 GiB      | 10.04 KiB         |     512823 | 4.91 GiB   | 10.04 KiB      |
| memory/innodb/hash0hash                       |             4 | 79.07 MiB     | 19.77 MiB         |          4 | 79.07 MiB  | 19.77 MiB      |
| memory/innodb/memory                          |         17096 | 31.68 MiB     | 1.90 KiB          |      22498 | 37.60 MiB  | 1.71 KiB       |
| memory/sql/String::value                      |        122277 | 27.94 MiB     |  239 bytes        |     124699 | 29.47 MiB  |  247 bytes     |
| memory/sql/TABLE                              |          9927 | 24.67 MiB     | 2.55 KiB          |       9929 | 24.68 MiB  | 2.55 KiB       |
| memory/innodb/lock0lock                       |          8888 | 19.71 MiB     | 2.27 KiB          |       8888 | 19.71 MiB  | 2.27 KiB       |
| memory/sql/Prepared_statement::infrastructure |        257623 | 16.24 MiB     |   66 bytes        |     257631 | 16.24 MiB  |   66 bytes     |
| memory/mysys/KEY_CACHE                        |             3 | 16.00 MiB     | 5.33 MiB          |          3 | 16.00 MiB  | 5.33 MiB       |
| memory/innodb/sync0arr                        |             3 | 7.03 MiB      | 2.34 MiB          |          3 | 7.03 MiB   | 2.34 MiB       |
| memory/sql/THD::main_mem_root                 |           815 | 6.56 MiB      | 8.24 KiB          |        849 | 7.19 MiB   | 8.67 KiB       |
+-----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
10 rows in set (0.06 sec)
```

从事件的名称中，我们可以看出此内存正用于预处理语句。如果您想查看哪些连接正在使用此内存，您可以检查 [memory\$1by\$1thread\$1by\$1current\$1bytes](https://dev.mysql.com/doc/refman/8.0/en/sys-memory-by-thread-by-current-bytes.html)。

在以下示例中，为每个连接分配了大约 7 MiB，历史最高水平约为 6.29 MiB (`current_max_alloc`)。这是有道理的，因为该示例正在将 `sysbench` 用于 80 个表和 800 个带有预处理语句的连接。如果您要在这种情况下减少内存使用量，可以优化应用程序对预处理语句的使用，来减少内存消耗。

```
mysql> SELECT * FROM sys.memory_by_thread_by_current_bytes;

+-----------+-------------------------------------------+--------------------+-------------------+-------------------+-------------------+-----------------+
| thread_id | user                                      | current_count_used | current_allocated | current_avg_alloc | current_max_alloc | total_allocated |
+-----------+-------------------------------------------+--------------------+-------------------+-------------------+-------------------+-----------------+
|        46 | rdsadmin@localhost                        |                405 | 8.47 MiB          | 21.42 KiB         | 8.00 MiB          | 155.86 MiB      |
|        61 | reinvent@10.0.4.4                         |               1749 | 6.72 MiB          | 3.93 KiB          | 6.29 MiB          | 14.24 MiB       |
|       101 | reinvent@10.0.4.4                         |               1845 | 6.71 MiB          | 3.72 KiB          | 6.29 MiB          | 14.50 MiB       |
|        55 | reinvent@10.0.4.4                         |               1674 | 6.68 MiB          | 4.09 KiB          | 6.29 MiB          | 14.13 MiB       |
|        57 | reinvent@10.0.4.4                         |               1416 | 6.66 MiB          | 4.82 KiB          | 6.29 MiB          | 13.52 MiB       |
|       112 | reinvent@10.0.4.4                         |               1759 | 6.66 MiB          | 3.88 KiB          | 6.29 MiB          | 14.17 MiB       |
|        66 | reinvent@10.0.4.4                         |               1428 | 6.64 MiB          | 4.76 KiB          | 6.29 MiB          | 13.47 MiB       |
|        75 | reinvent@10.0.4.4                         |               1389 | 6.62 MiB          | 4.88 KiB          | 6.29 MiB          | 13.40 MiB       |
|       116 | reinvent@10.0.4.4                         |               1333 | 6.61 MiB          | 5.08 KiB          | 6.29 MiB          | 13.21 MiB       |
|        90 | reinvent@10.0.4.4                         |               1448 | 6.59 MiB          | 4.66 KiB          | 6.29 MiB          | 13.58 MiB       |
|        98 | reinvent@10.0.4.4                         |               1440 | 6.57 MiB          | 4.67 KiB          | 6.29 MiB          | 13.52 MiB       |
|        94 | reinvent@10.0.4.4                         |               1433 | 6.57 MiB          | 4.69 KiB          | 6.29 MiB          | 13.49 MiB       |
|        62 | reinvent@10.0.4.4                         |               1323 | 6.55 MiB          | 5.07 KiB          | 6.29 MiB          | 13.48 MiB       |
|        87 | reinvent@10.0.4.4                         |               1323 | 6.55 MiB          | 5.07 KiB          | 6.29 MiB          | 13.25 MiB       |
|        99 | reinvent@10.0.4.4                         |               1346 | 6.54 MiB          | 4.98 KiB          | 6.29 MiB          | 13.24 MiB       |
|       105 | reinvent@10.0.4.4                         |               1347 | 6.54 MiB          | 4.97 KiB          | 6.29 MiB          | 13.34 MiB       |
|        73 | reinvent@10.0.4.4                         |               1335 | 6.54 MiB          | 5.02 KiB          | 6.29 MiB          | 13.23 MiB       |
|        54 | reinvent@10.0.4.4                         |               1510 | 6.53 MiB          | 4.43 KiB          | 6.29 MiB          | 13.49 MiB       |
.                                                                                                                                                          .
.                                                                                                                                                          .
.                                                                                                                                                          .
|       812 | reinvent@10.0.4.4                         |               1259 | 6.38 MiB          | 5.19 KiB          | 6.29 MiB          | 13.05 MiB       |
|       214 | reinvent@10.0.4.4                         |               1279 | 6.38 MiB          | 5.10 KiB          | 6.29 MiB          | 12.90 MiB       |
|       325 | reinvent@10.0.4.4                         |               1254 | 6.38 MiB          | 5.21 KiB          | 6.29 MiB          | 12.99 MiB       |
|       705 | reinvent@10.0.4.4                         |               1273 | 6.37 MiB          | 5.13 KiB          | 6.29 MiB          | 13.03 MiB       |
|       530 | reinvent@10.0.4.4                         |               1268 | 6.37 MiB          | 5.15 KiB          | 6.29 MiB          | 12.92 MiB       |
|       307 | reinvent@10.0.4.4                         |               1263 | 6.37 MiB          | 5.17 KiB          | 6.29 MiB          | 12.87 MiB       |
|       738 | reinvent@10.0.4.4                         |               1260 | 6.37 MiB          | 5.18 KiB          | 6.29 MiB          | 13.00 MiB       |
|       819 | reinvent@10.0.4.4                         |               1252 | 6.37 MiB          | 5.21 KiB          | 6.29 MiB          | 13.01 MiB       |
|        31 | innodb/srv_purge_thread                   |              17810 | 3.14 MiB          |  184 bytes        | 2.40 MiB          | 205.69 MiB      |
|        38 | rdsadmin@localhost                        |                599 | 1.76 MiB          | 3.01 KiB          | 1.00 MiB          | 25.58 MiB       |
|         1 | sql/main                                  |               3756 | 1.32 MiB          |  367 bytes        | 355.78 KiB        | 6.19 MiB        |
|       854 | rdsadmin@localhost                        |                 46 | 1.08 MiB          | 23.98 KiB         | 1.00 MiB          | 5.10 MiB        |
|        30 | innodb/clone_gtid_thread                  |               1596 | 573.14 KiB        |  367 bytes        | 254.91 KiB        | 970.69 KiB      |
|        40 | rdsadmin@localhost                        |                235 | 245.19 KiB        | 1.04 KiB          | 128.88 KiB        | 808.64 KiB      |
|       853 | rdsadmin@localhost                        |                 96 | 94.63 KiB         | 1009 bytes        | 29.73 KiB         | 422.45 KiB      |
|        36 | rdsadmin@localhost                        |                 33 | 36.29 KiB         | 1.10 KiB          | 16.08 KiB         | 74.15 MiB       |
|        33 | sql/event_scheduler                       |                  3 | 16.27 KiB         | 5.42 KiB          | 16.04 KiB         | 16.27 KiB       |
|        35 | sql/compress_gtid_table                   |                  8 | 14.20 KiB         | 1.77 KiB          | 8.05 KiB          | 18.62 KiB       |
|        25 | innodb/fts_optimize_thread                |                 12 | 1.86 KiB          |  158 bytes        |  648 bytes        | 1.98 KiB        |
|        23 | innodb/srv_master_thread                  |                 11 | 1.23 KiB          |  114 bytes        |  361 bytes        | 24.40 KiB       |
|        24 | innodb/dict_stats_thread                  |                 11 | 1.23 KiB          |  114 bytes        |  361 bytes        | 1.35 KiB        |
|         5 | innodb/io_read_thread                     |                  1 |  144 bytes        |  144 bytes        |  144 bytes        |  144 bytes      |
|         6 | innodb/io_read_thread                     |                  1 |  144 bytes        |  144 bytes        |  144 bytes        |  144 bytes      |
|         2 | sql/aws_oscar_log_level_monitor           |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|         4 | innodb/io_ibuf_thread                     |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|         7 | innodb/io_write_thread                    |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|         8 | innodb/io_write_thread                    |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|         9 | innodb/io_write_thread                    |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        10 | innodb/io_write_thread                    |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        11 | innodb/srv_lra_thread                     |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        12 | innodb/srv_akp_thread                     |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        18 | innodb/srv_lock_timeout_thread            |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |  248 bytes      |
|        19 | innodb/srv_error_monitor_thread           |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        20 | innodb/srv_monitor_thread                 |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        21 | innodb/buf_resize_thread                  |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        22 | innodb/btr_search_sys_toggle_thread       |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        32 | innodb/dict_persist_metadata_table_thread |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        34 | sql/signal_handler                        |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
+-----------+-------------------------------------------+--------------------+-------------------+-------------------+-------------------+-----------------+
831 rows in set (2.48 sec)
```

如前所述，此处的线程 ID (`thd_id`) 值可以指服务器后台线程或数据库连接。如果要将线程 ID 值映射到数据库连接 ID，则可以使用 `performance_schema.threads` 表或 `sys.processlist` 视图，其中 `conn_id` 是连接 ID。

```
mysql> SELECT thd_id,conn_id,user,db,command,state,time,last_wait FROM sys.processlist WHERE user='reinvent@10.0.4.4';

+--------+---------+-------------------+----------+---------+----------------+------+-------------------------------------------------+
| thd_id | conn_id | user              | db       | command | state          | time | last_wait                                       |
+--------+---------+-------------------+----------+---------+----------------+------+-------------------------------------------------+
|    590 |     562 | reinvent@10.0.4.4 | sysbench | Execute | closing tables |    0 | wait/io/redo_log_flush                          |
|    578 |     550 | reinvent@10.0.4.4 | sysbench | Sleep   | NULL           |    0 | idle                                            |
|    579 |     551 | reinvent@10.0.4.4 | sysbench | Execute | closing tables |    0 | wait/io/redo_log_flush                          |
|    580 |     552 | reinvent@10.0.4.4 | sysbench | Execute | updating       |    0 | wait/io/table/sql/handler                       |
|    581 |     553 | reinvent@10.0.4.4 | sysbench | Execute | updating       |    0 | wait/io/table/sql/handler                       |
|    582 |     554 | reinvent@10.0.4.4 | sysbench | Sleep   | NULL           |    0 | idle                                            |
|    583 |     555 | reinvent@10.0.4.4 | sysbench | Sleep   | NULL           |    0 | idle                                            |
|    584 |     556 | reinvent@10.0.4.4 | sysbench | Execute | updating       |    0 | wait/io/table/sql/handler                       |
|    585 |     557 | reinvent@10.0.4.4 | sysbench | Execute | closing tables |    0 | wait/io/redo_log_flush                          |
|    586 |     558 | reinvent@10.0.4.4 | sysbench | Execute | updating       |    0 | wait/io/table/sql/handler                       |
|    587 |     559 | reinvent@10.0.4.4 | sysbench | Execute | closing tables |    0 | wait/io/redo_log_flush                          |
.                                                                                                                                     .
.                                                                                                                                     .
.                                                                                                                                     .
|    323 |     295 | reinvent@10.0.4.4 | sysbench | Sleep   | NULL           |    0 | idle                                            |
|    324 |     296 | reinvent@10.0.4.4 | sysbench | Execute | updating       |    0 | wait/io/table/sql/handler                       |
|    325 |     297 | reinvent@10.0.4.4 | sysbench | Execute | closing tables |    0 | wait/io/redo_log_flush                          |
|    326 |     298 | reinvent@10.0.4.4 | sysbench | Execute | updating       |    0 | wait/io/table/sql/handler                       |
|    438 |     410 | reinvent@10.0.4.4 | sysbench | Execute | System lock    |    0 | wait/lock/table/sql/handler                     |
|    280 |     252 | reinvent@10.0.4.4 | sysbench | Sleep   | starting       |    0 | wait/io/socket/sql/client_connection            |
|     98 |      70 | reinvent@10.0.4.4 | sysbench | Query   | freeing items  |    0 | NULL                                            |
+--------+---------+-------------------+----------+---------+----------------+------+-------------------------------------------------+
804 rows in set (5.51 sec)
```

现在我们停止 `sysbench` 工作负载，这会关闭连接并释放内存。再次检查事件，我们可以确认内存已释放，但 `high_alloc` 仍然可以告诉我们历史最高水平是多少。`high_alloc` 列在识别内存使用量的短暂峰值时可能非常有用，在这种情况下，您可能无法根据 `current_alloc` 立即识别使用量，它仅显示当前分配的内存。

```
mysql> SELECT * FROM sys.memory_global_by_current_bytes WHERE event_name='memory/sql/Prepared_statement::main_mem_root' LIMIT 10;

+----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| event_name                                   | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc |
+----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| memory/sql/Prepared_statement::main_mem_root |            17 | 253.80 KiB    | 14.93 KiB         |     512823 | 4.91 GiB   | 10.04 KiB      |
+----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
1 row in set (0.00 sec)
```

如果要重置 `high_alloc`，可以截断 `performance_schema` 内存摘要表，但这会重置所有内存检测。有关更多信息，请参阅 MySQL 文档中的 [Performance Schema general table characteristics](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-table-characteristics.html)。

在下面的示例中，我们可以看到截断后重置 `high_alloc`。

```
mysql> TRUNCATE `performance_schema`.`memory_summary_global_by_event_name`;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM sys.memory_global_by_current_bytes WHERE event_name='memory/sql/Prepared_statement::main_mem_root' LIMIT 10;

+----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| event_name                                   | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc |
+----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| memory/sql/Prepared_statement::main_mem_root |            17 | 253.80 KiB    | 14.93 KiB         |         17 | 253.80 KiB | 14.93 KiB      |
+----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
1 row in set (0.00 sec)
```

## 示例 2：短暂内存峰值
<a name="ams-workload-memory.example2"></a>

另一种常见的情况是数据库服务器上的内存使用量出现短暂的峰值。这些可能是可释放内存的周期性下降，使用 `sys.memory_global_by_current_bytes` 中的 `current_alloc` 很难排除故障，因为内存已经被释放。

**注意**  
如果 Performance Schema 统计数据已重置，或者数据库实例已重启，则这些信息将无法在 `sys` 或 p`erformance_schema` 中找到。为保留该信息，建议您配置外部指标收集。

下图展示了增强监控中的 `os.memory.free` 指标，其中显示了内存使用量短暂的 7 秒峰值。增强监控让您能够以短至 1 秒的间隔进行监控，这非常适合捕捉此类短暂峰值。

![\[该图显示了随时间推移的短暂内存使用量峰值，周期性规律指示潜在的内存管理问题。\]](http://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/images/ams-free-memory-spikes.png)


为协助诊断此处内存使用量的原因，我们可以结合使用 `sys` 内存摘要视图中的 `high_alloc` 和 [Performance Schema statement summary tables](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-statement-summary-tables.html) 来尝试识别有问题的会话和连接。

正如预期的那样，由于目前内存使用量不高，因此我们在 `sys` 架构视图的 `current_alloc` 下看不到任何严重问题。

```
mysql> SELECT * FROM sys.memory_global_by_current_bytes LIMIT 10;

+-----------------------------------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| event_name                                                                  | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc |
+-----------------------------------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| memory/innodb/hash0hash                                                     |             4 | 79.07 MiB     | 19.77 MiB         |          4 | 79.07 MiB  | 19.77 MiB      |
| memory/innodb/os0event                                                      |        439372 | 60.34 MiB     |  144 bytes        |     439372 | 60.34 MiB  |  144 bytes     |
| memory/performance_schema/events_statements_summary_by_digest               |             1 | 40.28 MiB     | 40.28 MiB         |          1 | 40.28 MiB  | 40.28 MiB      |
| memory/mysys/KEY_CACHE                                                      |             3 | 16.00 MiB     | 5.33 MiB          |          3 | 16.00 MiB  | 5.33 MiB       |
| memory/performance_schema/events_statements_history_long                    |             1 | 14.34 MiB     | 14.34 MiB         |          1 | 14.34 MiB  | 14.34 MiB      |
| memory/performance_schema/events_errors_summary_by_thread_by_error          |           257 | 13.07 MiB     | 52.06 KiB         |        257 | 13.07 MiB  | 52.06 KiB      |
| memory/performance_schema/events_statements_summary_by_thread_by_event_name |             1 | 11.81 MiB     | 11.81 MiB         |          1 | 11.81 MiB  | 11.81 MiB      |
| memory/performance_schema/events_statements_summary_by_digest.digest_text   |             1 | 9.77 MiB      | 9.77 MiB          |          1 | 9.77 MiB   | 9.77 MiB       |
| memory/performance_schema/events_statements_history_long.digest_text        |             1 | 9.77 MiB      | 9.77 MiB          |          1 | 9.77 MiB   | 9.77 MiB       |
| memory/performance_schema/events_statements_history_long.sql_text           |             1 | 9.77 MiB      | 9.77 MiB          |          1 | 9.77 MiB   | 9.77 MiB       |
+-----------------------------------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
10 rows in set (0.01 sec)
```

将视图扩展为按 `high_alloc` 排序，我们现在可以看到，此处 `memory/temptable/physical_ram` 组件是一个非常好的候选组件。最高时，它消耗了 515.00 MiB。

顾名思义，`memory/temptable/physical_ram` 在 MySQL 中检测 `TEMP` 存储引擎的内存使用量（在 MySQL 8.0 中引入）。有关 MySQL 如何使用临时表的更多信息，请参阅 MySQL 文档中的 [Internal temporary table use in MySQL](https://dev.mysql.com/doc/refman/8.0/en/internal-temporary-tables.html)。

**注意**  
我们在该示例中使用 `sys.x$memory_global_by_current_bytes` 视图。

```
mysql> SELECT event_name, format_bytes(current_alloc) AS "currently allocated", sys.format_bytes(high_alloc) AS "high-water mark"  
FROM sys.x$memory_global_by_current_bytes ORDER BY high_alloc DESC LIMIT 10;

+-----------------------------------------------------------------------------+---------------------+-----------------+
| event_name                                                                  | currently allocated | high-water mark |
+-----------------------------------------------------------------------------+---------------------+-----------------+
| memory/temptable/physical_ram                                               | 4.00 MiB            | 515.00 MiB      |
| memory/innodb/hash0hash                                                     | 79.07 MiB           | 79.07 MiB       |
| memory/innodb/os0event                                                      | 63.95 MiB           | 63.95 MiB       |
| memory/performance_schema/events_statements_summary_by_digest               | 40.28 MiB           | 40.28 MiB       |
| memory/mysys/KEY_CACHE                                                      | 16.00 MiB           | 16.00 MiB       |
| memory/performance_schema/events_statements_history_long                    | 14.34 MiB           | 14.34 MiB       |
| memory/performance_schema/events_errors_summary_by_thread_by_error          | 13.07 MiB           | 13.07 MiB       |
| memory/performance_schema/events_statements_summary_by_thread_by_event_name | 11.81 MiB           | 11.81 MiB       |
| memory/performance_schema/events_statements_summary_by_digest.digest_text   | 9.77 MiB            | 9.77 MiB        |
| memory/performance_schema/events_statements_history_long.sql_text           | 9.77 MiB            | 9.77 MiB        |
+-----------------------------------------------------------------------------+---------------------+-----------------+
10 rows in set (0.00 sec)
```

在[示例 1：持续的高内存使用量](#ams-workload-memory.example1)中，我们检查了每个连接的当前内存使用量，来确定哪个连接负责使用相关内存。在此示例中，内存已被释放，因此检查当前连接的内存使用量并无用处。

为了更深入地挖掘并找到有问题的语句、用户和主机，我们使用 Performance Schema。Performance Schema 包含多个语句摘要表，这些摘要表按事件名称、语句摘要、主机、线程和用户等不同维度进行切片。每个视图都让您能够更深入地了解某些语句的运行位置以及它们的作用是什么。本节重点介绍 `MAX_TOTAL_MEMORY`，但您可以在 [Performance Schema statement summary tables](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-statement-summary-tables.html) 文档中找到有关所有可用列的更多信息。

```
mysql> SHOW TABLES IN performance_schema LIKE 'events_statements_summary_%';

+------------------------------------------------------------+
| Tables_in_performance_schema (events_statements_summary_%) |
+------------------------------------------------------------+
| events_statements_summary_by_account_by_event_name         |
| events_statements_summary_by_digest                        |
| events_statements_summary_by_host_by_event_name            |
| events_statements_summary_by_program                       |
| events_statements_summary_by_thread_by_event_name          |
| events_statements_summary_by_user_by_event_name            |
| events_statements_summary_global_by_event_name             |
+------------------------------------------------------------+
7 rows in set (0.00 sec)
```

首先，我们检查 `events_statements_summary_by_digest` 来查看 `MAX_TOTAL_MEMORY`。

从这里，我们可以看到以下内容：
+ 带有摘要 `20676ce4a690592ff05debcffcbc26faeb76f22005e7628364d7a498769d0c4a` 的查询似乎是这种内存使用量的一个很好的候选查询。`MAX_TOTAL_MEMORY` 为 537450710，与我们在 `sys.x$memory_global_by_current_bytes` 中看到的 `memory/temptable/physical_ram` 事件的历史最高水平相符。
+ 它已经运行了四次 (`COUNT_STAR`)，第一次是在 2024-03-26 04:08:34.943256，最后一次是在 2024-03-26 04:43:06.998310。

```
mysql> SELECT SCHEMA_NAME,DIGEST,COUNT_STAR,MAX_TOTAL_MEMORY,FIRST_SEEN,LAST_SEEN
FROM performance_schema.events_statements_summary_by_digest ORDER BY MAX_TOTAL_MEMORY DESC LIMIT 5;

+-------------+------------------------------------------------------------------+------------+------------------+----------------------------+----------------------------+
| SCHEMA_NAME | DIGEST                                                           | COUNT_STAR | MAX_TOTAL_MEMORY | FIRST_SEEN                 | LAST_SEEN                  |
+-------------+------------------------------------------------------------------+------------+------------------+----------------------------+----------------------------+
| sysbench    | 20676ce4a690592ff05debcffcbc26faeb76f22005e7628364d7a498769d0c4a |          4 |        537450710 | 2024-03-26 04:08:34.943256 | 2024-03-26 04:43:06.998310 |
| NULL        | f158282ea0313fefd0a4778f6e9b92fc7d1e839af59ebd8c5eea35e12732c45d |          4 |          3636413 | 2024-03-26 04:29:32.712348 | 2024-03-26 04:36:26.269329 |
| NULL        | 0046bc5f642c586b8a9afd6ce1ab70612dc5b1fd2408fa8677f370c1b0ca3213 |          2 |          3459965 | 2024-03-26 04:31:37.674008 | 2024-03-26 04:32:09.410718 |
| NULL        | 8924f01bba3c55324701716c7b50071a60b9ceaf17108c71fd064c20c4ab14db |          1 |          3290981 | 2024-03-26 04:31:49.751506 | 2024-03-26 04:31:49.751506 |
| NULL        | 90142bbcb50a744fcec03a1aa336b2169761597ea06d85c7f6ab03b5a4e1d841 |          1 |          3131729 | 2024-03-26 04:15:09.719557 | 2024-03-26 04:15:09.719557 |
+-------------+------------------------------------------------------------------+------------+------------------+----------------------------+----------------------------+
5 rows in set (0.00 sec)
```

现在我们知道了有问题的摘要，我们可以获得更多详细信息，例如查询文本、运行它的用户以及运行它的位置。根据返回的摘要文本，我们可以看到这是一个公用表表达式（CTE），它创建了四个临时表并执行了四次表扫描，效率非常低。

```
mysql> SELECT SCHEMA_NAME,DIGEST_TEXT,QUERY_SAMPLE_TEXT,MAX_TOTAL_MEMORY,SUM_ROWS_SENT,SUM_ROWS_EXAMINED,SUM_CREATED_TMP_TABLES,SUM_NO_INDEX_USED
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST='20676ce4a690592ff05debcffcbc26faeb76f22005e7628364d7a498769d0c4a'\G;

*************************** 1. row ***************************
           SCHEMA_NAME: sysbench
           DIGEST_TEXT: WITH RECURSIVE `cte` ( `n` ) AS ( SELECT ? FROM `sbtest1` UNION ALL SELECT `id` + ? FROM `sbtest1` ) SELECT * FROM `cte`
     QUERY_SAMPLE_TEXT: WITH RECURSIVE cte (n) AS (   SELECT 1  from sbtest1 UNION ALL   SELECT id + 1 FROM sbtest1) SELECT * FROM cte
      MAX_TOTAL_MEMORY: 537450710
         SUM_ROWS_SENT: 80000000
     SUM_ROWS_EXAMINED: 80000000
SUM_CREATED_TMP_TABLES: 4
     SUM_NO_INDEX_USED: 4
1 row in set (0.01 sec)
```

有关 `events_statements_summary_by_digest` 表和其它 Performance Schema 语句摘要表的更多信息，请参阅 MySQL 文档中的 [Statement summary tables](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-statement-summary-tables.html)。

您也可以运行 [EXPLAIN](https://dev.mysql.com/doc/refman/8.0/en/explain.html) 或 [EXPLAIN ANALYZE](https://dev.mysql.com/doc/refman/8.0/en/explain.html#explain-analyze) 语句来查看更多详细信息。

**注意**  
`EXPLAIN ANALYZE` 可以比 `EXPLAIN` 提供更多的信息，但它也会运行查询，所以要小心。

```
-- EXPLAIN
mysql> EXPLAIN WITH RECURSIVE cte (n) AS (SELECT 1  FROM sbtest1 UNION ALL SELECT id + 1 FROM sbtest1) SELECT * FROM cte;

+----+-------------+------------+------------+-------+---------------+------+---------+------+----------+----------+-------------+
| id | select_type | table      | partitions | type  | possible_keys | key  | key_len | ref  | rows     | filtered | Extra       |
+----+-------------+------------+------------+-------+---------------+------+---------+------+----------+----------+-------------+
|  1 | PRIMARY     | <derived2> | NULL       | ALL   | NULL          | NULL | NULL    | NULL | 19221520 |   100.00 | NULL        |
|  2 | DERIVED     | sbtest1    | NULL       | index | NULL          | k_1  | 4       | NULL |  9610760 |   100.00 | Using index |
|  3 | UNION       | sbtest1    | NULL       | index | NULL          | k_1  | 4       | NULL |  9610760 |   100.00 | Using index |
+----+-------------+------------+------------+-------+---------------+------+---------+------+----------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)

-- EXPLAIN format=tree 
mysql> EXPLAIN format=tree WITH RECURSIVE cte (n) AS (SELECT 1 FROM sbtest1 UNION ALL SELECT id + 1 FROM sbtest1) SELECT * FROM cte\G;

*************************** 1. row ***************************
EXPLAIN: -> Table scan on cte  (cost=4.11e+6..4.35e+6 rows=19.2e+6)
    -> Materialize union CTE cte  (cost=4.11e+6..4.11e+6 rows=19.2e+6)
        -> Index scan on sbtest1 using k_1  (cost=1.09e+6 rows=9.61e+6)
        -> Index scan on sbtest1 using k_1  (cost=1.09e+6 rows=9.61e+6)
1 row in set (0.00 sec)

-- EXPLAIN ANALYZE 
mysql> EXPLAIN ANALYZE WITH RECURSIVE cte (n) AS (SELECT 1 from sbtest1 UNION ALL SELECT id + 1 FROM sbtest1) SELECT * FROM cte\G;

*************************** 1. row ***************************
EXPLAIN: -> Table scan on cte  (cost=4.11e+6..4.35e+6 rows=19.2e+6) (actual time=6666..9201 rows=20e+6 loops=1)
    -> Materialize union CTE cte  (cost=4.11e+6..4.11e+6 rows=19.2e+6) (actual time=6666..6666 rows=20e+6 loops=1)
        -> Covering index scan on sbtest1 using k_1  (cost=1.09e+6 rows=9.61e+6) (actual time=0.0365..2006 rows=10e+6 loops=1)
        -> Covering index scan on sbtest1 using k_1  (cost=1.09e+6 rows=9.61e+6) (actual time=0.0311..2494 rows=10e+6 loops=1)
1 row in set (10.53 sec)
```

但谁运行它呢？ 我们可以在 Performance Schema 中看到，`destructive_operator` 用户拥有 `MAX_TOTAL_MEMORY` 537450710，这再次与之前的结果相符。

**注意**  
 Performance Schema 存储在内存中，因此不应将其作为审计的唯一来源。如果您需要维护语句运行的历史记录以及语句是由哪些用户运行的，我们建议启用 [Aurora 高级审计](AuroraMySQL.Auditing.md)。如果您还需要维护有关内存使用量的信息，建议您将监控配置为导出和存储这些值。

```
mysql> SELECT USER,EVENT_NAME,COUNT_STAR,MAX_TOTAL_MEMORY FROM performance_schema.events_statements_summary_by_user_by_event_name
ORDER BY MAX_CONTROLLED_MEMORY DESC LIMIT 5;

+----------------------+---------------------------+------------+------------------+
| USER                 | EVENT_NAME                | COUNT_STAR | MAX_TOTAL_MEMORY |
+----------------------+---------------------------+------------+------------------+
| destructive_operator | statement/sql/select      |          4 |        537450710 |
| rdsadmin             | statement/sql/select      |       4172 |          3290981 |
| rdsadmin             | statement/sql/show_tables |          2 |          3615821 |
| rdsadmin             | statement/sql/show_fields |          2 |          3459965 |
| rdsadmin             | statement/sql/show_status |         75 |          1914976 |
+----------------------+---------------------------+------------+------------------+
5 rows in set (0.00 sec)

mysql> SELECT HOST,EVENT_NAME,COUNT_STAR,MAX_TOTAL_MEMORY FROM performance_schema.events_statements_summary_by_host_by_event_name
WHERE HOST != 'localhost' AND COUNT_STAR>0 ORDER BY MAX_CONTROLLED_MEMORY DESC LIMIT 5;

+------------+----------------------+------------+------------------+
| HOST       | EVENT_NAME           | COUNT_STAR | MAX_TOTAL_MEMORY |
+------------+----------------------+------------+------------------+
| 10.0.8.231 | statement/sql/select |          4 |        537450710 |
+------------+----------------------+------------+------------------+
1 row in set (0.00 sec)
```

## 示例 3：可释放内存持续下降且无法回收
<a name="ams-workload-memory.example3"></a>

InnoDB 数据库引擎为不同的组件使用了一系列专门的内存跟踪事件。这些特定事件允许精细跟踪 InnoDB 关键子系统的内存使用情况，例如：
+ `memory/innodb/buf0buf` – 专门用于监控 InnoDB 缓冲池的内存分配。
+ `memory/innodb/ibuf0ibuf` – 专门跟踪与 InnoDB 更改缓冲区相关的内存变化。

为了确定内存的最大使用者，我们可以查询 `sys.memory_global_by_current_bytes`：

```
mysql> SELECT event_name,current_alloc FROM sys.memory_global_by_current_bytes LIMIT 10;

+-----------------------------------------------------------------+---------------+
| event_name                                                      | current_alloc |
+-----------------------------------------------------------------+---------------+
| memory/innodb/memory                                            | 5.28 GiB      |
| memory/performance_schema/table_io_waits_summary_by_index_usage | 495.00 MiB    |
| memory/performance_schema/table_shares                          | 488.00 MiB    |
| memory/sql/TABLE_SHARE::mem_root                                | 388.95 MiB    |
| memory/innodb/std                                               | 226.88 MiB    |
| memory/innodb/fil0fil                                           | 198.49 MiB    |
| memory/sql/binlog_io_cache                                      | 128.00 MiB    |
| memory/innodb/mem0mem                                           | 96.82 MiB     |
| memory/innodb/dict0dict                                         | 96.76 MiB     |
| memory/performance_schema/rwlock_instances                      | 88.00 MiB     |
+-----------------------------------------------------------------+---------------+
10 rows in set (0.00 sec)
```

结果表明，`memory/innodb/memory` 是最大使用者，使用了 5.28 GiB 当前分配的内存。此事件用作与更具体的等待事件（如前所述的 `memory/innodb/buf0buf`）无关的各种 InnoDB 组件的内存分配类别。

在确定了 InnoDB 组件是内存的主要使用者之后，我们就可以使用以下 MySQL 命令更深入地研究具体细节：

```
SHOW ENGINE INNODB STATUS \G;
```

[SHOW ENGINE INNODB STATUS](https://dev.mysql.com/doc/refman/8.4/en/show-engine.html) 命令为 InnoDB 存储引擎提供全面的状态报告，包括不同 InnoDB 组件的详细内存使用统计信息。它可以帮助确定哪些特定的 InnoDB 结构或操作消耗内存最多。有关更多信息，请参阅 MySQL 文档中的 [InnoDB in-memory structures](https://dev.mysql.com/doc/refman/8.0/en/innodb-in-memory-structures.html)。

分析 InnoDB 状态报告的 `BUFFER POOL AND MEMORY` 部分后，我们可以看到，5,051,647,748 字节（4.7 GiB）分配给了[字典对象缓存](https://dev.mysql.com/doc/refman/8.0/en/data-dictionary-object-cache.html)，占比为 `memory/innodb/memory` 所跟踪内存的 89%。

```
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 0
Dictionary memory allocated 5051647748
Buffer pool size 170512
Free buffers 142568
Database pages 27944
Old database pages 10354
Modified db pages 6
Pending reads 0
```

字典对象缓存是一种共享全局缓存，它将以前访问过的数据字典对象存储在内存中，以实现对象的重复使用并提高性能。对字典对象缓存的高内存分配表明数据字典缓存中有大量数据库对象。

既然知道了数据字典缓存是主要使用者，我们接下来检查数据字典缓存中是否有打开的表。要查找表定义缓存中的表数量，请查询全局状态变量 [open\$1table\$1definitions](https://dev.mysql.com/doc/refman/8.4/en/server-status-variables.html#statvar_Open_table_definitions)。

```
mysql> show global status like 'open_table_definitions';

+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| Open_table_definitions | 20000 |
+------------------------+-------+
1 row in set (0.00 sec)
```

有关更多信息，请参阅 MySQL 文档中的 [MySQL 如何打开和关闭表](https://dev.mysql.com/doc/refman/8.0/en/table-cache.html)。

您可以通过限制数据库集群或数据库实例参数组中的 `table_definition_cache` 参数，来限制数据字典缓存中表定义的数量。对于 Aurora MySQL，此值用作表定义缓存中表数量的软限制。默认值取决于实例类并设置为以下值：

```
LEAST({DBInstanceClassMemory/393040}, 20000)
```

当表的数量超过 `table_definition_cache` 限制时，最近最少使用（LRU）机制会将表从缓存中移出并删除。但是，涉及外键关系的表不会放在 LRU 列表中，以防止其被删除。

在我们当前的场景中，我们运行 [FLUSH TABLES](https://dev.mysql.com/doc/refman/8.4/en/flush.html) 来清除表定义缓存。此操作会导致 [Open\$1table\$1definitions](https://dev.mysql.com/doc/refman/8.0/en/server-status-variables.html#statvar_Open_table_definitions) 全局状态变量从 20,000 大幅下降到 12，如下所示：

```
mysql> show global status like 'open_table_definitions';

+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| Open_table_definitions | 12    |
+------------------------+-------+
1 row in set (0.00 sec)
```

尽管有如此的减少，但我们观察到 `memory/innodb/memory` 的内存分配依然很高，为 5.18 GiB，且分配的字典内存也未变。从以下查询结果中可以明显看出这一点：

```
mysql> SELECT event_name,current_alloc FROM sys.memory_global_by_current_bytes LIMIT 10;

+-----------------------------------------------------------------+---------------+
| event_name                                                      | current_alloc |
+-----------------------------------------------------------------+---------------+
| memory/innodb/memory                                            | 5.18 GiB      |
| memory/performance_schema/table_io_waits_summary_by_index_usage | 495.00 MiB    |
| memory/performance_schema/table_shares                          | 488.00 MiB    |
| memory/sql/TABLE_SHARE::mem_root                                | 388.95 MiB    |
| memory/innodb/std                                               | 226.88 MiB    |
| memory/innodb/fil0fil                                           | 198.49 MiB    |
| memory/sql/binlog_io_cache                                      | 128.00 MiB    |
| memory/innodb/mem0mem                                           | 96.82 MiB     |
| memory/innodb/dict0dict                                         | 96.76 MiB     |
| memory/performance_schema/rwlock_instances                      | 88.00 MiB     |
+-----------------------------------------------------------------+---------------+
10 rows in set (0.00 sec)
```

```
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 0
Dictionary memory allocated 5001599639
Buffer pool size 170512
Free buffers 142568
Database pages 27944
Old database pages 10354
Modified db pages 6
Pending reads 0
```

这种持续的高内存使用量可以归因于涉及外键关系的表。这些表没有放在 LRU 列表中，无法删除，这就解释了为什么即使在刷新了表定义缓存之后，内存分配依然很高。

解决此问题：

1. 查看和优化您的数据库架构，尤其是外键关系。

1. 可以考虑改用具有更大内存的更大的数据库实例类来容纳您的字典对象。

通过执行这些步骤并了解内存分配模式，您可以更好地管理 Aurora MySQL 数据库实例中的内存使用情况，并防止由于内存压力而导致的潜在性能问题。

# 排查 Aurora MySQL 数据库内存不足问题
<a name="AuroraMySQLOOM"></a>

Aurora MySQL `aurora_oom_response` 实例级参数可以使数据库实例能够监控系统内存，并估计各种语句和连接消耗的内存。如果系统内存不足，它可能会执行一系列操作，来尝试释放该内存。这样做的目的是试图避免由于内存不足（OOM）问题而导致数据库重启。该实例级参数使用一串以逗号分隔的操作，在内存不足时，数据库实例将执行这些操作。Aurora MySQL 版本 2 和 3 支持 `aurora_oom_response` 参数。

以下值及其组合可用于 `aurora_oom_response` 参数。空字符串表示未执行任何操作，实际上是关闭此功能，使数据库易于 OOM 重启。
+ `decline` – 在数据库实例出现内存不足时，拒绝新的查询。
+ `kill_connect` – 关闭消耗大量内存的数据库连接，并结束当前事务和数据定义语言（DDL）语句。Aurora MySQL 版本 2 不支持此响应。

  有关更多信息，请参阅 MySQL 文档中的 [KILL statement](https://dev.mysql.com/doc/refman/8.0/en/kill.html)。
+ `kill_query` – 按内存消耗量降序结束查询，直到实例内存高于下限阈值。未结束 DDL 语句。

  有关更多信息，请参阅 MySQL 文档中的 [KILL statement](https://dev.mysql.com/doc/refman/8.0/en/kill.html)。
+ `print` – 仅输出占用大量内存的查询。
+ `tune` – 调整内部表缓存以将一些内存释放回系统。在内存不足的情况下，Aurora MySQL 会减少用于缓存（例如 `table_open_cache` 和 `table_definition_cache`）的内存。最终，当系统不再内存不足时，Aurora MySQL 会将其内存使用率恢复正常。

  有关更多信息，请参阅 MySQL 文档中的 [table\$1open\$1cache](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_table_open_cache) 和 [table\$1definition\$1cache](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_table_definition_cache)。
+ `tune_buffer_pool` – 减小缓冲池的大小以释放一些内存，使数据库服务器可以使用这些内存来处理连接。Aurora MySQL 版本 3.06 及更高版本支持此响应。

  您必须在 `aurora_oom_response` 参数值中将 `tune_buffer_pool` 或 `kill_query` 与 `kill_connect` 进行配对。否则，即使您在参数值中包含 `tune_buffer_pool`，也无法调整缓冲池的大小。

在低于 3.06 的 Aurora MySQL 版本中，对于内存小于或等于 4GiB 的数据库实例类，当实例面临内存压力时，默认操作包括 `print`、`tune`、`decline` 和 `kill_query`。对于内存大于 4GiB 的数据库实例类，该参数值默认为空（已禁用）。

在 Aurora MySQL 版本 3.06 及更高版本中，对于内存小于或等于 4 GiB 的数据库实例类，Aurora MySQL 还会关闭占用内存最高的连接（`kill_connect`）。对于内存大于 4 GiB 的数据库实例类，默认参数值为 `print`。

在 Aurora MySQL 版本 3.09 及更高版本中，对于内存大于 4 GiB 的数据库实例类，默认参数值为 `print,decline,kill_connect`。

如果您经常遇到内存不足问题，则启用 `performance_schema` 后，可以使用[内存摘要表](https://dev.mysql.com/doc/refman/8.3/en/performance-schema-memory-summary-tables.html)来监控内存使用情况。

有关与 OOM 相关的 Amazon CloudWatch 指标，请参阅 [Amazon Aurora 的实例级指标](Aurora.AuroraMonitoring.Metrics.md#Aurora.AuroraMySQL.Monitoring.Metrics.instances)。有关与 OOM 相关的全局状态变量，请参阅 [Aurora MySQL 全局状态变量](AuroraMySQL.Reference.GlobalStatusVars.md)。

# Aurora MySQL 数据库日志记录
<a name="aurora-mysql-troubleshooting-logging"></a>

Aurora MySQL 日志提供有关数据库活动和错误的基本信息。通过启用这些日志，您可以识别和排查问题，了解数据库性能并审计数据库活动。我们建议您为所有 Aurora MySQL 数据库实例启用这些日志，来确保数据库的最佳性能和可用性。可以启用以下类型的日志记录。每个日志都包含特定的信息，这些信息可以揭示对数据库处理的影响。
+ 错误 – Aurora MySQL 仅在启动、关闭和遇到错误时，才向错误日志写入内容。数据库实例可以运行数小时或者数天，而不向错误日志中写入新项。如果看不到最近的条目，则原因是服务器未遇到导致生成日志条目的错误。默认情况下，启用错误日志记录。有关更多信息，请参阅 [Aurora MySQL 错误日志](USER_LogAccess.MySQL.LogFileSize.md#USER_LogAccess.MySQL.Errorlog)。
+ 常规 - 常规日志提供有关数据库活动的详细信息，包括数据库引擎执行的所有 SQL 语句。有关启用常规日志记录和设置日志记录参数的更多信息，请参阅 [Aurora MySQL 慢速查询日志和一般日志](USER_LogAccess.MySQL.LogFileSize.md#USER_LogAccess.MySQL.Generallog)和 MySQL 文档中的 [The general query log](https://dev.mysql.com/doc/refman/8.0/en/query-log.html)。
**注意**  
常规日志可能会增长到非常大，并占用您的存储空间。有关更多信息，请参阅 [Aurora MySQL 的日志轮换和保留](USER_LogAccess.MySQL.LogFileSize.md#USER_LogAccess.AMS.LogFileSize.retention)。
+ 慢速查询 – 慢速查询日志包含运行时间超过 [long\$1query\$1time](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_long_query_time) 秒且需要至少检查 [min\$1examined\$1row\$1limit](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_min_examined_row_limit) 行的 SQL 语句。您可以使用慢速查询日志来查找运行时间长、因而适合进行优化的查询。

  `long_query_time` 的默认值是 10 秒。我们建议您从较高的值开始来确定最慢的查询，然后逐渐向下进行微调。

  您也可以使用相关参数，例如 `log_slow_admin_statements` 和 `log_queries_not_using_indexes`。将 `rows_examined` 与 `rows_returned` 进行比较。如果 `rows_examined` 比 `rows_returned` 大得多，则这些查询可能会被阻止。

  在 Aurora MySQL 版本 3 中，您可以启用 `log_slow_extra` 来获取更多详细信息。有关更多信息，请参阅 MySQL 文档中的 [Slow query log contents](https://dev.mysql.com/doc/refman/8.0/en/slow-query-log.html#slow-query-log-contents)。您还可以在会话级别修改 `long_query_time`，以便以交互方式调试查询执行，这在全局启用 `log_slow_extra` 时尤其有用。

  有关启用慢速查询日志记录和设置日志记录参数的更多信息，请参阅 [Aurora MySQL 慢速查询日志和一般日志](USER_LogAccess.MySQL.LogFileSize.md#USER_LogAccess.MySQL.Generallog)和 MySQL 文档中的 [The slow query log](https://dev.mysql.com/doc/refman/8.0/en/slow-query-log.html)。
+ 审计 - 审计日志监控并记录数据库活动。Aurora MySQL 的审计日志记录称为高级审计。要启用高级审计，应设置某些数据库集群参数。有关更多信息，请参阅 [在 Amazon Aurora MySQL 数据库集群中使用高级审计](AuroraMySQL.Auditing.md)。
+ 二进制 – 二进制日志（binlog）包含描述数据库更改的事件，例如表创建操作和对表数据的更改。它还包含可能已进行更改的语句的事件（例如，不匹配任何行的 [DELETE](https://dev.mysql.com/doc/refman/8.0/en/delete.html)），除非使用基于行的日志记录。二进制日志还包含有关更新数据的每条语句所花时间的信息。

  在启用了二进制日志记录的情况下运行服务器会使性能稍微下降。但是，二进制日志使您能够设置复制和执行还原操作，所带来的好处通常会超过这一轻微的性能下降。
**注意**  
Aurora MySQL 不需要使用二进制日志记录来执行还原操作。

  有关启用二进制日志记录和设置二进制日志格式的更多信息，请参阅[为单可用区数据库配置 Aurora MySQL 二进制日志记录](USER_LogAccess.MySQL.BinaryFormat.md)以及 MySQL 文档中的 [The binary log](https://dev.mysql.com/doc/refman/8.0/en/binary-log.html)。

您可以将错误日志、常规日志、慢速日志、查询日志和审计日志发布到 Amazon CloudWatch Logs。有关更多信息，请参阅 [将数据库日志发布到 Amazon CloudWatch Logs](USER_LogAccess.Procedural.UploadtoCloudWatch.md)。

另一个用于汇总慢速日志文件、常规日志文件和二进制日志文件的有用工具是 [pt-query-digest](https://docs.percona.com/percona-toolkit/pt-query-digest.html)。

# 排查 Aurora MySQL 数据库的连接问题
<a name="mysql-troubleshooting-dbconn"></a>

确保应用程序和 RDS 数据库实例之间的可靠连接对于工作负载的平稳运行至关重要。但是，各种因素（例如网络配置、身份验证问题或资源限制）可能会导致出现连接问题。本指南旨在提供一种全面的方法来排查 Aurora MySQL 的连接问题。

**Contents**
+ [

## 识别 Aurora MySQL 的数据库连接问题
](#mysql-dbconn-identify)
+ [

## 收集有关 Aurora MySQL 连接问题的数据
](#mysql-dbconn-gather)
+ [

## 监控 Aurora MySQL 的数据库连接
](#mysql-dbconn-monitor)
  + [

### Aurora MySQL 的额外监控
](#mysql-dbconn-monitor-ams)
+ [

## Aurora MySQL 的连接错误代码
](#mysql-dbconn-errors)
+ [

## Aurora MySQL 的参数调优建议
](#mysql-dbconn-params)
+ [

## 排查 Aurora MySQL 数据库连接问题的示例
](#mysql-dbconn-examples)
  + [

### 示例 1：排查失败的连接尝试
](#mysql-dbconn-example1)
  + [

### 示例 2：排查异常客户端断开连接问题
](#mysql-dbconn-example2)
  + [

### 示例 3：排查 IAM 失败的连接尝试
](#mysql-dbconn-example3)

## 识别 Aurora MySQL 的数据库连接问题
<a name="mysql-dbconn-identify"></a>

识别连接问题的具体类别有助于缩小潜在原因范围并指导问题排查过程。每个类别可能需要不同的诊断和解决方法与技术。数据库连接问题可以大致分为以下几类。

**连接错误和异常**  
出现连接错误和异常的原因有多种，例如连接字符串不正确、身份验证失败、网络中断或数据库服务器问题。原因可能包括连接参数配置错误、凭证无效、网络中断或数据库服务器崩溃或重新启动。安全组配置错误、虚拟私有云（VPC）设置、网络访问控制列表（ACL）以及与子网关联的路由表也可能导致连接问题。

**已达到连接限制**  
当数据库服务器的并发连接数超过允许的最大限制时，就会出现此问题。数据库服务器通常具有可配置的最大连接限制，该限制由集群和实例参数组中的参数 max\$1connections 定义。通过施加连接限制，数据库服务器可确保拥有足够的资源（例如内存、CPU 和文件句柄）来有效地处理现有连接并提供可接受的性能。原因可能包括应用程序中的连接泄漏、连接池效率低下或连接请求意外激增。

**连接超时**  
当客户端应用程序无法在指定的超时期间与数据库服务器建立连接时，就会发生连接超时。常见原因包括网络问题、服务器过载、防火墙规则和连接设置配置错误。

**空闲连接超时**  
为了节省资源，数据库服务器可能会自动关闭长时间处于非活动状态的空闲连接。此超时通常可使用 `wait_timeout` 和 `interactive_timeout parameters` 进行配置，并且应根据应用程序的连接使用模式进行调整。原因可能包括应用程序逻辑使连接长时间处于空闲状态，或者连接管理不当。

**间歇性断开现有连接**  
此类错误是指这样一种情况：尽管客户端应用程序和数据库之间已建立的连接处于活动状态并正在使用中，但仍意外终止或不定期断开连接。这些断开连接是间歇性发生的，意味着它们以不规则的间隔发生，而且不一致。原因可以包括：  
+ 数据库服务器问题，例如重新启动或失效转移
+ 应用程序连接处理不当
+ 负载均衡和代理问题
+ 网络不稳定
+ 连接路径中涉及第三方组件或中间件的问题
+ 查询执行超时
+ 服务器端或客户端的资源限制
通过全面的监控、日志记录和分析来确定根本原因至关重要，而实施适当的错误处理、连接池和重试机制有助于减轻这些间歇性断开连接对应用程序功能和用户体验的影响。

## 收集有关 Aurora MySQL 连接问题的数据
<a name="mysql-dbconn-gather"></a>

收集与应用程序、数据库、网络和基础设施组件相关的全面数据对于有效排查应用程序与 Aurora MySQL 数据库之间的连接问题至关重要。通过收集相关的日志、配置和诊断信息，可以获得宝贵的见解，这些见解能够帮助您确定连接问题的根本原因并指导您找到适当的解决方案。

网络日志和配置（例如安全组规则、VPC 设置和路由表）对于识别可能阻碍应用程序成功与数据库建立连接的潜在网络相关瓶颈或错误配置至关重要。通过分析这些网络组件，您可以确保已打开必要的端口，已允许 IP 地址，并已正确设置路由配置。

**时间戳**  
记录发生连接问题时的确切时间戳。这有助于识别模式或将问题与其他事件或活动相关联。

**数据库引擎日志**  
除了常规数据库日志外，还要查看数据库引擎日志（例如，MySQL 错误日志和慢速查询日志），以了解可能与间歇性连接问题相关的任何相关信息或错误。有关更多信息，请参阅 [Aurora MySQL 数据库日志记录](aurora-mysql-troubleshooting-logging.md)。

**客户端应用程序日志**  
从连接到数据库的客户端应用程序收集详细日志。应用程序日志从应用程序的角度提供有关连接尝试和错误的信息以及任何相关信息，从而揭示与连接字符串、身份验证凭证或应用程序级连接处理有关的问题。  
而数据库日志让您可以深入了解数据库端错误、慢速查询或可能导致连接问题的事件。有关更多信息，请参阅 [Aurora MySQL 数据库日志记录](aurora-mysql-troubleshooting-logging.md)。

**客户端环境变量**  
检查客户端上的任何环境变量或配置设置是否可能影响数据库连接，例如代理设置、SSL/TLS 设置或任何其他相关变量。

**客户端库版本**  
确保客户端使用的是用于数据库连接的所有数据库驱动程序、库或框架的最新版本。过时的版本可能存在已知问题或兼容性问题。

**客户端网络捕获**  
出现连接问题时，使用诸如 Wireshark 或 `tcpdump` 之类的工具在客户端执行网络捕获。这有助于在客户端识别任何网络相关问题或异常。

**客户端网络拓扑**  
了解客户端的网络拓扑，包括任何防火墙、负载均衡器或其他组件，例如 RDS 代理或 Proxy SQL，这些组件与数据库建立连接，而不是客户端直接建立连接。

**客户端操作系统设置**  
检查可能影响网络连接的客户端操作系统设置，例如防火墙规则、网络适配器设置以及任何其他相关设置。

**连接池配置**  
如果您在应用程序中使用连接池机制，请查看配置设置并监控池指标（例如，活动连接、空闲连接和连接超时），以确保池正常运行。还要查看池设置（例如最大池大小、最小池大小和连接验证设置）以确保配置正确。

**连接字符串**  
连接字符串通常包括诸如主机名或端点、端口号、数据库名称和身份验证凭证之类的参数。分析连接字符串有助于识别可能导致连接问题的潜在错误配置或不正确设置。例如，错误的主机名或端口号可能会阻止客户端访问数据库实例，而无效的身份验证凭证可能导致身份验证失败和连接被拒绝。此外，连接字符串可以揭示与连接池、超时或其他特定于连接的设置（可能导致连接问题）有关的问题。提供客户端应用程序使用的完整连接字符串有助于查明客户端上的任何错误配置。

**数据库指标**  
出现连接问题时，监控 CPU 使用率、内存使用量和磁盘 I/O 等数据库指标。这些有助于确定数据库实例是否存在资源争用或性能问题。

**数据库引擎版本**  
请注意 Aurora MySQL 数据库引擎版本。AWS 定期发布更新以解决已知问题和安全漏洞，并引入性能增强功能。因此，强烈建议您升级到最新的可用版本，因为这些更新通常包含与连接性、性能和稳定性特别相关的错误修复和改进。提供数据库版本信息以及收集的其他详细信息可以帮助 支持 有效地诊断和解决连接问题。

**网络指标**  
出现连接问题时，收集延迟、数据包丢失和吞吐量等网络指标。`ping` 和 `traceroute` 等工具以及网络监控工具可以帮助收集这些数据。

**源和客户端详细信息**  
确定正在启动数据库连接的应用程序服务器、负载均衡器或任何其他组件的 IP 地址。这可以是单个 IP 地址，也可以是 IP 地址范围（CIDR 表示法）。如果源是 Amazon EC2 实例，则查看实例类型、可用区、子网 ID 和与该实例关联的安全组以及网络接口详细信息（例如私有 IP 地址和公有 IP 地址）也会有所帮助。

通过全面分析所收集的数据，您可以识别导致间歇性或持续连接问题的错误配置、资源限制、网络中断或其他潜在问题。您可以根据这些信息采取有针对性的措施，例如调整配置、解决网络问题或进行应用程序级连接处理。

## 监控 Aurora MySQL 的数据库连接
<a name="mysql-dbconn-monitor"></a>

要监控和排查连接问题，可以使用以下指标和功能。

**CloudWatch 指标**  
+ `CPUUtilization` – 如果数据库实例上的 CPU 使用率过高，可能会导致查询执行缓慢，从而导致连接超时或被拒绝。
+ `DatabaseConnections` – 监控数据库实例的活动连接数。如果连接数接近配置的最大值，则表明可能存在连接问题或连接池已耗尽。
+ `FreeableMemory` – 由于资源限制，可用内存不足可能会导致性能问题和连接问题。
+ `NetworkReceiveThroughput` 和 `NetworkTransmitThroughput` – 网络吞吐量的异常峰值或下降可能表明存在连接问题或网络瓶颈。

**性能详情指标**  
要利用性能详情排查 Aurora MySQL 中的连接问题，请分析如下所示的数据库指标：  
+ Aborted\$1clients
+ Aborted\$1connects
+ 连接
+ max\$1connections
+ Threads\$1connected
+ Threads\$1created
+ Threads\$1running
这些指标可帮助您识别连接瓶颈，检测网络或身份验证问题，优化连接池并确保高效的线程管理。有关更多信息，请参阅 [Aurora MySQL 的性能详情计数器](USER_PerfInsights_Counters.md#USER_PerfInsights_Counters.Aurora_MySQL)。

**性能详情特征**  
+ **数据库负载** – 可视化一段时间内的数据库负载，并将其与连接问题或性能下降相关联。
+ **SQL 统计数据** – 分析 SQL 统计数据，以识别可能导致连接问题的低效查询或数据库操作。
+ **热门查询** – 识别和分析资源密集度高的查询，这有助于识别可能导致连接问题的潜在性能瓶颈或长时间运行的查询。

通过监控这些指标并利用性能详情，您可以了解数据库实例的性能、资源使用情况以及可能导致连接问题的潜在瓶颈。例如：
+ 接近最大限制的高 `DatabaseConnections` 值可能表明连接池已耗尽或连接处理不当，从而导致连接问题。
+ 高 `CPUUtilization` 或低 `FreeableMemory` 可能表明资源限制，这可能会导致查询执行缓慢以及连接超时或被拒绝。
+ 分析**热门查询**和 **SQL 统计数据**有助于识别可能导致连接问题的低效查询或资源密集型查询。

此外，监控 CloudWatch Logs 和设置警报可帮助您在连接问题升级之前主动识别问题并做出响应。

值得注意的是，虽然这些指标和工具可以提供有价值的见解，但它们应与其他故障排除步骤结合使用。如果再查看网络配置、安全组规则和应用程序级连接处理，则可以全面诊断和解决 Aurora MySQL 数据库实例的连接问题。

### Aurora MySQL 的额外监控
<a name="mysql-dbconn-monitor-ams"></a>

**CloudWatch 指标**  
+ `AbortedClients` – 跟踪未正确关闭的客户端连接数量。
+ `AuroraSlowConnectionHandleCount` – 跟踪慢速连接句柄操作的数量，指出潜在的连接问题或性能瓶颈。
+ `AuroraSlowHandshakeCount` – 测量慢速握手操作的数量，这也可以作为连接问题的指标。
+ `ConnectionAttempts` – 测量尝试连接 Aurora MySQL 数据库实例的次数。

**全局状态变量**  
`Aurora_external_connection_count` – 显示与数据库实例的数据库连接数，不包括用于数据库运行状况检查的 RDS 服务连接。

通过监控这些指标和全局状态变量，您可以了解可能导致 Amazon Aurora MySQL 实例出现连接问题的连接模式、错误和潜在瓶颈。

例如，`AbortedClients` 或 `AuroraSlowConnectionHandleCount` 数量过多可能表明存在连接问题。

此外，设置 CloudWatch 警报和通知可帮助您在连接问题升级并影响应用程序性能之前主动识别问题并做出响应。

## Aurora MySQL 的连接错误代码
<a name="mysql-dbconn-errors"></a>

以下是 Aurora MySQL 数据库的一些常见连接错误及其错误代码和说明。

**错误代码 1040：连接过多**  
当客户端尝试建立的连接数超过数据库服务器允许的最大连接数时，就会发生此错误。可能的原因包括：  
+ 连接池配置错误 – 如果使用连接池机制，请确保最大池大小不要设置得太高，并且连接正确释放回池中。
+ 数据库实例配置 – 验证数据库实例的最大允许连接数设置，并在必要时通过设置 `max_connections` 参数进行调整。
+ 高并发 – 如果多个客户端或应用程序同时连接到数据库，则可能会达到允许的最大连接限制。

**错误代码 1045：用户“...”@“...”的访问被拒绝（使用密码：是/否）**  
此错误表示尝试连接到数据库时身份验证失败。可能的原因包括：  
+ 身份验证插件兼容性 – 检查客户端使用的身份验证插件是否与数据库服务器的身份验证机制兼容。
+ 用户名或密码不正确 – 验证连接字符串或身份验证机制中使用的用户名和密码是否正确。
+ 用户权限 – 确保用户拥有从指定主机或网络连接到数据库实例所需的权限。

**错误代码 1049：未知数据库“...”**  
此错误表示客户端正试图连接到服务器上不存在的数据库。可能的原因包括：  
+ 数据库未创建 – 确保数据库服务器上已创建指定的数据库。
+ 数据库名称不正确 – 仔细检查连接字符串或查询中使用的数据库名称是否准确。
+ 用户权限 – 验证用户是否拥有访问指定数据库所需的权限。

**错误代码 1153：数据包大于“max\$1allowed\$1packet”字节**  
当客户端尝试发送或接收超出数据库服务器允许的最大数据包大小的数据时，就会发生此错误。可能的原因包括：  
+ 大型查询或结果集 – 如果执行的查询涉及大量数据，则可能会超过数据包大小限制。
+ 错误配置的数据包大小设置 – 检查数据库服务器上的 `max_allowed_packet` 设置并在必要时进行调整。
+ 网络配置问题 – 确保网络配置（例如 MTU 大小）允许所需的数据包大小。

**错误代码 1226：用户“...”已超出“max\$1user\$1connections”资源（当前值：...）**  
此错误表示用户已超过数据库服务器允许的最大并发连接数。可能的原因包括：  
+ 连接池配置错误 – 如果使用连接池机制，请确保最大池大小不要设置得太高，以免超出用户的连接限制。
+ 数据库实例配置 – 验证数据库实例的 `max_user_connections` 设置，并在必要时进行调整。
+ 高并发 – 如果多个客户端或应用程序使用相同的用户同时连接到数据库，则可能会达到特定于用户的连接限制。

**错误代码 2003：无法通过“...”连接到 MySQL 服务器（10061）**  
当客户端无法与数据库服务器建立 TCP/IP 连接时，通常会发生此错误。这可能由多种问题引起，例如：  
+ 数据库实例状态 – 确保数据库实例处于 `available` 状态，且未进行任何维护或备份操作。
+ 防火墙规则 – 检查是否有任何防火墙（操作系统、网络或安全组）在阻止指定端口（对于 MySQL，通常为 3306）上的连接。
+ 主机名或端点不正确 – 确保连接字符串中使用的主机名或端点正确且与数据库实例相匹配。
+ 网络连接问题 – 验证客户端计算机是否可以通过网络访问数据库实例。检查是否存在任何网络中断、路由问题或者 VPC 或子网配置错误。

**错误代码 2005：未知的 MySQL 服务器主机“...”（11001）**  
当客户端无法将数据库服务器的主机名或端点解析为 IP 地址时，就会发生此错误。可能的原因包括：  
+ DNS 解析问题 – 验证客户端计算机是否可以使用 DNS 正确解析主机名。检查 DNS 设置、DNS 缓存，然后尝试使用 IP 地址而不是主机名。
+ 主机名或端点不正确 – 仔细检查连接字符串中使用的主机名或端点是否准确。
+ 网络配置问题 – 确保客户端的网络配置（例如 VPC、子网和路由表）允许进行 DNS 解析和连接到数据库实例。

**错误代码 2026：SSL 连接错误**  
在尝试连接期间，当 SSL/TLS 配置或证书验证出现问题时，就会发生此错误。可能的原因包括：  
+ 证书过期 – 检查服务器使用的 SSL/TLS 证书是否已过期并需要续订。
+ 证书验证问题 – 验证客户端是否能够正确验证服务器的 SSL/TLS 证书，以及该证书是否可信。
+ 网络配置问题 – 确保网络配置允许 SSL/TLS 连接，并且不会阻塞或干扰 SSL/TLS 握手过程。
+ SSL/TLS 配置不匹配 – 确保客户端和服务器上的 SSL/TLS 设置（例如，密码套件和协议版本）兼容。

通过了解每个错误代码的详细说明和潜在原因，在使用 Aurora MySQL 数据库时，您可以更好地排查和解决连接问题。

## Aurora MySQL 的参数调优建议
<a name="mysql-dbconn-params"></a>

**最大连接数**  
调整这些参数有助于防止由于达到允许的最大连接限制而导致的连接问题。确保根据应用程序的并发要求和资源限制适当设置这些值。  
+ `max_connections` – 此参数指定数据库实例允许的最大并发连接数。
+ `max_user_connections` – 可以在用户创建和修改过程中指定此参数，并设置特定用户账户允许的最大并发连接数。

**网络缓冲区大小**  
增加这些值可以提高网络性能，特别是对于涉及大型数据传输或结果集的工作负载。但请谨慎行事，因为较大的缓冲区大小会占用更多内存。  
+ `net_buffer_length` – 此参数设置客户端连接和结果缓冲区的初始大小，从而平衡内存使用量和查询性能。
+ `max_allowed_packet` – 此参数指定数据库实例可以发送或接收的单个网络数据包的最大大小。

**网络压缩（客户端）**  
启用网络压缩可以减少网络带宽使用量，但会增加客户端和服务器端的 CPU 开销。  
+ `compress` – 此参数启用或禁用客户端/服务器通信的网络压缩。
+ `compress_protocol` – 此参数指定用于网络通信的压缩协议。

**网络性能调优**  
调整这些超时有助于管理空闲连接并防止资源耗尽，但要谨慎行事，因为较低的值可能会导致连接过早终止。  
+ `interactive_timeout` – 此参数指定服务器在关闭交互式连接之前等待活动的秒数。
+ `wait_timeout` – 此参数确定服务器在关闭非交互式连接之前等待活动的秒数。

**网络超时设置**  
调整这些超时有助于解决与连接速度慢或无响应有关的问题。但注意不要将它们设置得太低，否则可能会导致连接过早失败。  
+ `net_read_timeout` – 此参数指定在结束读取操作之前等待来自连接的更多数据的秒数。
+ `net_write_timeout` – 此参数确定在结束写入操作之前等待数据块写入连接的秒数。

## 排查 Aurora MySQL 数据库连接问题的示例
<a name="mysql-dbconn-examples"></a>

以下示例说明如何识别和排查 Aurora MySQL 的数据库连接问题。

### 示例 1：排查失败的连接尝试
<a name="mysql-dbconn-example1"></a>

连接尝试失败可能有多种原因，包括身份验证失败、SSL/TLS 握手失败、达到 `max_connections` 限制以及数据库实例上的资源限制。

您可以通过性能详情或使用以下命令来跟踪失败的连接数。

```
mysql> show global status like 'aborted_connects';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| Aborted_connects | 7     |
+------------------+-------+
1 row in set (0.00 sec)
```

如果 `Aborted_connects` 数随着时间的推移而增加，则应用程序可能会出现间歇性连接问题。

您可以使用 [Aurora 高级审计](AuroraMySQL.Auditing.md)来记录客户端的连接和断开连接情况。您可以通过在数据库集群参数组中设置以下参数来执行此操作：
+ `server_audit_logging` = `1`
+ `server_audit_events` = `CONNECT`

 以下是登录失败的审计日志摘录。

```
1728498527380921,auora-mysql-node1,user_1,172.31.49.222,147189,0,FAILED_CONNECT,,,1045
1728498527380940,auora-mysql-node1,user_1,172.31.49.222,147189,0,DISCONNECT,,,0
```

其中：
+ `1728498527380921` – 登录失败发生时的纪元时间戳
+ `aurora-mysql-node1` – 连接失败的 Aurora MySQL 集群节点的实例标识符
+ `user_1` – 登录失败的数据库用户的名称
+ `172.31.49.222` – 建立连接的客户端的私有 IP 地址
+ `147189` – 登录失败的连接 ID
+ `FAILED_CONNECT` – 表示连接失败。
+ `1045` – 返回代码。非零值表示错误。在本例中，`1045` 对应于访问被拒绝。

有关更多信息，请参阅 MySQL 文档中的[服务器错误代码](https://dev.mysql.com/doc/mysql-errors/5.7/en/server-error-reference.html)和[客户端错误代码](https://dev.mysql.com/doc/mysql-errors/5.7/en/client-error-reference.html)。

 您还可以检查 Aurora MySQL 错误日志中是否存在任何相关的错误消息，例如：

```
2024-10-09T19:26:59.310443Z 220 [Note] [MY-010926] [Server] Access denied for user 'user_1'@'172.31.49.222' (using password: YES) (sql_authentication.cc:1502)
```

### 示例 2：排查异常客户端断开连接问题
<a name="mysql-dbconn-example2"></a>

您可以通过性能详情或使用以下命令来跟踪异常客户端断开连接数。

```
mysql> show global status like 'aborted_clients';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| Aborted_clients | 9     |
+-----------------+-------+
1 row in set (0.01 sec)
```

如果 `Aborted_clients` 数随着时间的推移而增加，则说明应用程序无法正确关闭与数据库的连接。如果连接未正确关闭，则可能导致资源泄漏和潜在的性能问题。不必要地使连接保持打开状态会消耗系统资源（例如内存和文件描述符），最终可能导致应用程序或服务器失去响应或重新启动。

您可以使用以下查询来识别未正确关闭连接的账户。它检索用户账户名称、用户进行连接所在的主机、未关闭的连接数以及未关闭的连接所占的百分比。

```
SELECT
    ess.user,
    ess.host,
    (a.total_connections - a.current_connections) - ess.count_star AS not_closed,
    (((a.total_connections - a.current_connections) - ess.count_star) * 100) / (a.total_connections - a.current_connections) AS pct_not_closed
FROM
    performance_schema.events_statements_summary_by_account_by_event_name AS ess
    JOIN performance_schema.accounts AS a ON (ess.user = a.user AND ess.host = a.host)
WHERE
    ess.event_name = 'statement/com/quit'
    AND (a.total_connections - a.current_connections) > ess.count_star;

+----------+---------------+------------+----------------+
| user     | host          | not_closed | pct_not_closed |
+----------+---------------+------------+----------------+
| user1    | 172.31.49.222 |          1 |        33.3333 |
| user1    | 172.31.93.250 |       1024 |        12.1021 |
| user2    | 172.31.93.250 |         10 |        12.8551 |
+----------+---------------+------------+----------------+
3 rows in set (0.00 sec)
```

确定未关闭连接的用户账户和主机后，您可以继续检查未正常关闭连接的代码。

例如，通过 Python 中的 MySQL 连接器，使用连接对象的 `close()` 方法来关闭连接。以下是建立数据库连接、执行查询和关闭连接的示例函数：

```
import mysql.connector

def execute_query(query):
    # Establish a connection to the database
    connection = mysql.connector.connect(
        host="your_host",
        user="your_username",
        password="your_password",
        database="your_database"
    )

    try:
        # Create a cursor object
        cursor = connection.cursor()

        # Execute the query
        cursor.execute(query)

        # Fetch and process the results
        results = cursor.fetchall()
        for row in results:
            print(row)

    finally:
        # Close the cursor and connection
        cursor.close()
        connection.close()
```

在此示例中，在 `finally` 数据块中调用 `connection.close()` 方法以确保无论是否发生异常，连接均已关闭。

### 示例 3：排查 IAM 失败的连接尝试
<a name="mysql-dbconn-example3"></a>

与 AWS Identity and Access Management（IAM）用户的连接可能由于若干原因而失败，例如：
+ IAM 策略配置不正确
+ 安全凭证到期
+ 网络连接问题
+ 数据库权限不匹配

要对这些身份验证错误进行故障排除，请在 Amazon Relational Database Service（RDS）或 Aurora 数据库中启用 `iam-db-auth-error` 日志导出功能。这可让您在 CloudWatch 日志组中查看 Amazon RDS 或 Amazon Aurora 集群的详细身份验证错误消息。

启用后，您可以查看这些日志，以确定并解决导致 IAM 身份验证失败的具体原因。

例如：

```
2025-09-22T12:02:30,806 [ERROR] Failed to authorize the connection request for user 'user_1' due to an internal IAM DB Auth error. (Status Code: 500, Error Code: InternalError)
```

以及

```
2025-09-22T12:02:51,954 [ERROR] Failed to authenticate the connection request for user 'user_2' because the provided token is malformed or otherwise invalid. (Status Code: 400, Error Code: InvalidToken)
```

有关故障排除指南，请参阅 IAM 数据库身份验证的 [Aurora](UsingWithRDS.IAMDBAuth.Troubleshooting.md) 故障排除指南。

# 排除 Aurora MySQL 数据库的查询性能故障
<a name="aurora-mysql-troubleshooting-query"></a>

MySQL 通过系统变量（它们影响评估查询计划的方式）、可切换的优化、优化器和索引提示以及优化器成本模型，来提供[查询优化器控制](https://dev.mysql.com/doc/refman/8.0/en/controlling-optimizer.html)。这些数据点不仅有助于比较不同的 MySQL 环境，还可以用来比较以前的查询执行计划和当前的执行计划，以及随时了解 MySQL 查询的总体执行情况。

查询性能取决于许多因素，包括执行计划、表架构和大小、统计信息、资源、索引和参数配置。查询调优要求识别瓶颈并优化执行路径。
+ 找到查询的执行计划，并检查查询是否正在使用适当的索引。您可以通过使用 `EXPLAIN` 和查看每个计划的详细信息来优化查询。
+ Aurora MySQL 版本 3（与 MySQL 8.0 社区版兼容）使用 `EXPLAIN ANALYZE` 语句。`EXPLAIN ANALYZE` 语句是一个分析工具，可显示 MySQL 在查询的哪些方面花费了时间以及原因。借助 `EXPLAIN ANALYZE`，Aurora MySQL 计划、准备和运行查询，同时计算行数并测量在执行计划的各个点花费的时间。查询完成后，`EXPLAIN ANALYZE` 输出计划及其测量值，而不是查询结果。
+ 通过使用 `ANALYZE` 语句使架构统计信息保持更新。查询优化器有时会因为统计信息过时而选择较差的执行计划。这可能会导致查询性能不佳，因为表和索引的基数估计值都不准确。[innodb\$1table\$1stats](https://dev.mysql.com/doc/refman/8.0/en/innodb-persistent-stats.html#innodb-persistent-stats-tables) 表的 `last_update` 列显示了上次更新架构统计信息的时间，这可以很好地表明是否“过时”。
+ 可能会出现其它问题，例如数据的分布偏斜，而表基数没有考虑这些问题。有关更多信息，请参阅 MySQL 文档中的 [Estimating ANALYZE TABLE complexity for InnoDB tables](https://dev.mysql.com/doc/refman/8.0/en/innodb-analyze-table-complexity.html) 和 [Histogram statistics in MySQL](https://dev.mysql.com/blog-archive/histogram-statistics-in-mysql/)。

## 了解查询所花的时间
<a name="ams-query-time"></a>

以下是确定查询所花时间的方法：
+ [分析](https://dev.mysql.com/doc/refman/8.0/en/show-profile.html)
+ [性能模式](https://dev.mysql.com/doc/refman/8.0/en/performance-schema.html)
+ [查询优化器](https://dev.mysql.com/doc/refman/8.0/en/controlling-optimizer.html)

**分析**  
默认情况下，分析功能处于禁用状态。启用分析功能，然后运行慢速查询并查看其分析结果。  

```
SET profiling = 1;
Run your query.
SHOW PROFILE;
```

1. 确定花费时间最多的阶段。根据 MySQL 文档中的[常规线程状态](https://dev.mysql.com/doc/refman/8.0/en/general-thread-states.html)，读取和处理 `SELECT` 语句的行通常是在给定查询的生命周期内运行时间最长的状态。您可以使用 `EXPLAIN` 语句来了解 MySQL 如何运行此查询。

1. 查看慢速查询日志来评估 `rows_examined` 和 `rows_sent`，来确保每个环境中的工作负载相似。有关更多信息，请参阅 [Aurora MySQL 数据库日志记录](aurora-mysql-troubleshooting-logging.md)。

1. 对属于已识别查询的一部分的表运行以下命令：

   ```
   SHOW TABLE STATUS\G;
   ```

1. 在每个环境上运行查询之前和之后捕获以下输出：

   ```
   SHOW GLOBAL STATUS;
   ```

1. 在每个环境上运行以下命令，来查看是否有任何其它查询/会话影响此示例查询的性能。

   ```
   SHOW FULL PROCESSLIST;
   
   SHOW ENGINE INNODB STATUS\G;
   ```

   有时，当服务器上的资源繁忙时，它会影响服务器上的每个其它操作，包括查询。您还可以在运行查询时定期捕获信息，或者设置 `cron` 任务来按有用的间隔捕获信息。

**性能模式**  
性能模式提供有关服务器运行时性能的有用信息，同时对该性能的影响最小。这与提供有关数据库实例的模式信息的 `information_schema` 不同。有关更多信息，请参阅 [Aurora MySQL 上性能详情的性能架构概述](USER_PerfInsights.EnableMySQL.md)。

**查询优化器跟踪**  
为了理解为什么选择特定的[查询计划来执行](https://dev.mysql.com/doc/refman/8.0/en/execution-plan-information.html)，您可以设置 `optimizer_trace` 来访问 MySQL 查询优化器。  
运行优化器跟踪，来显示有关优化器可用的所有路径及其选择的大量信息。  

```
SET SESSION OPTIMIZER_TRACE="enabled=on"; 
SET optimizer_trace_offset=-5, optimizer_trace_limit=5;

-- Run your query.
SELECT * FROM table WHERE x = 1 AND y = 'A';

-- After the query completes:
SELECT * FROM information_schema.OPTIMIZER_TRACE;
SET SESSION OPTIMIZER_TRACE="enabled=off";
```

## 查看查询优化器设置
<a name="ams-query-parameters"></a>

Aurora MySQL 版本 3（与 MySQL 8.0 社区版兼容）与 Aurora MySQL 版本 2（与 MySQL 5.7 社区版兼容）相比，前者具有许多与优化器相关的更改。如果您对于 `optimizer_switch` 有一些自定义值，我们建议您查看默认值的差异，并设置最适合您的工作负载的 `optimizer_switch` 值。我们还建议您测试可用于 Aurora MySQL 版本 3 的选项，来检查查询的执行情况。

**注意**  
Aurora MySQL 版本 3 对于 [innodb\$1stats\$1persistent\$1sample\$1pages](https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_stats_persistent_sample_pages) 参数使用社区默认值 20。

您可以使用以下命令来显示 `optimizer_switch` 值：

```
SELECT @@optimizer_switch\G;
```

下表显示 Aurora MySQL 版本 2 和 3 的默认 `optimizer_switch` 值。


| 设置 | Aurora MySQL 版本 2 | Aurora MySQL 版本 3 | 
| --- | --- | --- | 
| batched\$1key\$1access | off | off | 
| block\$1nested\$1loop | on | on | 
| condition\$1fanout\$1filter | on | on | 
| derived\$1condition\$1pushdown | – | on | 
| derived\$1merge | on | on | 
| duplicateweedout | on | on | 
| engine\$1condition\$1pushdown | on | on | 
| firstmatch | on | on | 
| hash\$1join | off | on | 
| hash\$1join\$1cost\$1based | on | – | 
| hypergraph\$1optimizer | – | off | 
| index\$1condition\$1pushdown | on | on | 
| index\$1merge | on | on | 
| index\$1merge\$1intersection | on | on | 
| index\$1merge\$1sort\$1union | on | on | 
| index\$1merge\$1union | on | on | 
| loosescan | on | on | 
| materialization | on | on | 
| mrr | on | on | 
| mrr\$1cost\$1based | on | on | 
| prefer\$1ordering\$1index | on | on | 
| semijoin | on | on | 
| skip\$1scan | – | on | 
| subquery\$1materialization\$1cost\$1based | on | on | 
| subquery\$1to\$1derived | – | off | 
| use\$1index\$1extensions | on | on | 
| use\$1invisible\$1indexes | – | off | 

有关更多信息，请参阅 MySQL 文档中的 [Switchable optimizations (MySQL 5.7)](https://dev.mysql.com/doc/refman/5.7/en/switchable-optimizations.html) 和 [Switchable optimizations (MySQL 8.0)](https://dev.mysql.com/doc/refman/8.0/en/switchable-optimizations.html) 。