

# 避免固定 RDS 代理
<a name="rds-proxy-pinning"></a>

 当数据库请求不依赖于先前请求的状态信息时，多路复用效率更高。在这种情况下，RDS 代理可以在每个事务结束时重用连接。此类状态信息的示例包括可通过 `SET` 或 `SELECT` 语句更改的大多数变量和配置参数。默认情况下，客户端连接上的 SQL 事务可以在底层数据库连接之间多路复用。

 与代理的连接可以进入一种称为*固定*的状态。固定连接后，每个后续事务将使用相同的底层数据库连接，直到会话结束。在会话结束之前，其他客户端连接也不能重用该数据库连接。客户端连接断开时，会话结束。

 当 RDS 代理检测到不适合其他会话的会话状态更改时，它会自动将客户端连接固定到特定的数据库连接。固定降低了连接重用的有效性。如果您的所有连接或几乎所有连接都遇到固定问题，请考虑修改应用程序代码或工作负载，以减少导致固定问题的情形。

例如，您的应用程序更改了会话变量或配置参数。在这种情况下，后面的语句可能依赖于新变量或参数来生效。因此，当 RDS 代理处理更改会话变量或配置设置的请求时，它会将该会话固定到数据库连接。这样，会话状态对于同一会话中的所有后续事务仍然有效。

 对于某些数据库引擎，此规则并不适用于您可以设置的全部参数。RDS 代理会跟踪某些语句和变量。因此，在您修改这些内容时，RDS 代理不会固定会话。在这种情况下，RDS 代理仅将连接重用于具有相同设置值的其他会话。有关 RDS 代理针对数据库引擎跟踪的内容的详细信息，请参阅以下内容：
+ [RDS 代理针对 RDS for SQL Server 数据库跟踪的内容](#rds-proxy-pinning.sql-server-tracked-vars)
+ [RDS 代理针对 RDS for MariaDB 数据库和 RDS for MySQL 数据库跟踪的内容](#rds-proxy-pinning.mysql-tracked-vars)

## RDS 代理针对 RDS for SQL Server 数据库跟踪的内容
<a name="rds-proxy-pinning.sql-server-tracked-vars"></a>

RDS 代理跟踪以下 SQL Server 语句：
+ `USE`
+ `SET ANSI_NULLS`
+ `SET ANSI_PADDING`
+ `SET ANSI_WARNINGS`
+ `SET ARITHABORT`
+ `SET CONCAT_NULL_YIELDS_NULL`
+ `SET CURSOR_CLOSE_ON_COMMIT`
+ `SET DATEFIRST`
+ `SET DATEFORMAT`
+ `SET LANGUAGE`
+ `SET LOCK_TIMEOUT`
+ `SET NUMERIC_ROUNDABORT`
+ `SET QUOTED_IDENTIFIER`
+ `SET TEXTSIZE`
+ `SET TRANSACTION ISOLATION LEVEL`

## RDS 代理针对 RDS for MariaDB 数据库和 RDS for MySQL 数据库跟踪的内容
<a name="rds-proxy-pinning.mysql-tracked-vars"></a>

RDS 代理跟踪以下 MariaDB 和 MySQL 语句：
+ DROP DATABASE
+ DROP SCHEMA
+ USE

RDS 代理跟踪以下 MySQL 和 MariaDB 变量：
+ `AUTOCOMMIT`
+ `AUTO_INCREMENT_INCREMENT`
+ `CHARACTER SET (or CHAR SET)`
+ `CHARACTER_SET_CLIENT`
+ `CHARACTER_SET_DATABASE`
+ `CHARACTER_SET_FILESYSTEM`
+ `CHARACTER_SET_CONNECTION`
+ `CHARACTER_SET_RESULTS`
+ `CHARACTER_SET_SERVER`
+ `COLLATION_CONNECTION`
+ `COLLATION_DATABASE`
+ `COLLATION_SERVER`
+ `INTERACTIVE_TIMEOUT`
+ `NAMES`
+ `NET_WRITE_TIMEOUT`
+ `QUERY_CACHE_TYPE`
+ `SESSION_TRACK_SCHEMA`
+ `SQL_MODE`
+ `TIME_ZONE`
+ `TRANSACTION_ISOLATION (or TX_ISOLATION)`
+ `TRANSACTION_READ_ONLY (or TX_READ_ONLY)`
+ `WAIT_TIMEOUT`

**注意**  
当您在会话范围内设置 `TRANSACTION_ISOLATION` 和 `TRANSACTION_READ_ONLY` 变量时，RDS 代理会跟踪对这些变量的更改。但是，如果在下一个事务范围内设置它们，RDS 代理将固定连接。无论您使用 `SET` 语句还是 `SET TRANSACTION` 语句来配置这些值，此行为都适用。

## 显著减少固定
<a name="rds-proxy-pinning.minimizing"></a>

 RDS 代理的性能优化包括尝试通过最小化固定来最大化事务级别连接重用（多路复用）。

您可以执行以下步骤以显著减少固定：
+  避免可能导致固定的不必要的数据库请求。
+  在所有连接中一致地设置变量和配置设置。这样，后续会话更有可能重用具有这些特定设置的连接。

   但是，对于 PostgreSQL 设置，变量会导致会话固定。
+  对于 MySQL 引擎系列数据库，可将会话固定筛选条件应用于代理。您可以免除某些类型的操作，使其不固定会话（如果您知道这样做不会影响应用程序的正确操作）。
+  通过监控 Amazon CloudWatch 指标 `DatabaseConnectionsCurrentlySessionPinned` 来查看固定的发生频率。有关该指标和其他 CloudWatch 指标的信息，请参阅 [使用 Amazon CloudWatch 监控 RDS Proxy 指标使用 CloudWatch 监控 RDS Proxy](rds-proxy.monitoring.md)。
+  如果您使用 `SET` 语句为每个客户端连接执行相同的初始化，则可以在保留事务级别多路复用的同时执行此操作。在这种情况下，您将设置初始会话状态的语句移动到由代理使用的初始化查询中。该属性是一个字符串，包含一个或多个 SQL 语句（用分号分隔）。

   例如，您可以为设置特定配置参数的代理定义初始化查询。然后，每当为该代理设置新连接时，RDS 代理都会应用这些设置。您可以从应用程序代码中删除相应的 `SET` 语句，这样，它们就不会干扰事务级别多路复用。

   有关代理的固定发生频率的指标，请参阅 [使用 Amazon CloudWatch 监控 RDS Proxy 指标使用 CloudWatch 监控 RDS Proxy](rds-proxy.monitoring.md)。

## 导致对所有引擎系列进行固定的条件
<a name="rds-proxy-pinning.all"></a>

 对于以下情况（其中多路复用可能会导致意外行为），代理将会话固定到当前连接：
+ 文本大小大于 16 KB 的任何语句都会导致代理固定会话。

## 导致对 RDS for Microsoft SQL Server 进行固定的条件
<a name="rds-proxy-pinning.sqlserver"></a>

 对于 RDS for SQL Server，以下交互也会导致固定：
+ 使用多个活动的结果集（MARS）。有关 MARS 的信息，请参阅 [SQL Server](https://docs.microsoft.com/en-us/sql/relational-databases/native-client/features/using-multiple-active-result-sets-mars?view=sql-server-ver16) 文档。
+ 使用分布式事务协调器（DTC）通信。
+ 创建临时表、事务、游标或预准备语句。
+ 使用以下 `SET` 语句：
  + `SET ANSI_DEFAULTS`
  + `SET ANSI_NULL_DFLT`
  + `SET ARITHIGNORE`
  + `SET DEADLOCK_PRIORITY`
  + `SET FIPS_FLAGGER`
  + `SET FMTONLY`
  + `SET FORCEPLAN`
  + `SET IDENTITY_INSERT`
  + `SET NOCOUNT`
  + `SET NOEXEC`
  + `SET OFFSETS`
  + `SET PARSEONLY`
  + `SET QUERY_GOVERNOR_COST_LIMIT`
  + `SET REMOTE_PROC_TRANSACTIONS`
  + `SET ROWCOUNT`
  + `SET SHOWPLAN_ALL`、`SHOWPLAN_TEXT` 和 `SHOWPLAN_XML`
  + `SET STATISTICS`
  + `SET XACT_ABORT`

## 导致对 RDS for MariaDB 和 RDS for MySQL 进行固定的条件
<a name="rds-proxy-pinning.mysql"></a>

 对于 MariaDB 和 MySQL，以下交互也会导致固定：
+ 显式表锁定语句 `LOCK TABLE`、`LOCK TABLES` 或 `FLUSH TABLES WITH READ LOCK` 会导致代理固定会话。
+ 通过使用 `GET_LOCK` 创建命名锁会导致代理固定会话。
+ 设置用户变量或系统变量（有些例外）会将会话固定到代理。如果这种情况严重限制了连接的重用，您可以配置 `SET` 操作以避免固定。为此，请调整会话固定筛选条件属性。有关更多信息，请参阅[为 Amazon RDS 创建代理](rds-proxy-creating.md)和[修改 RDS 代理](rds-proxy-modifying-proxy.md)。
+ 创建临时表会导致代理固定会话。这样，无论事务边界如何，临时表的内容都会在整个会话期间保留。
+ 调用 `ROW_COUNT` 和 `FOUND_ROWS` 函数有时会导致固定问题。
+ 预编译语句会导致代理固定会话。无论预编译语句使用 SQL 文本还是二进制协议，这项规则都适用。
+ 使用 SET LOCAL 时，RDS 代理无法固定连接。
+ 调用存储过程和存储函数不会导致固定。RDS 代理不会检测此类调用导致的任何会话状态更改。如果您希望跨事务持久保持存储例程中的会话状态，请确保您的应用程序不会更改该状态。例如，RDS 代理目前与创建跨所有事务持久存在的临时表的存储过程不兼容。
+ 带 MySQL 可执行注释（语法 /\$1\$1 ... \$1/）或 MariaDB 可执行注释（语法 /\$1M\$1 ... \$1/）的查询会导致停滞。RDS 代理无法解析嵌入在这些注释中的 SQL 来跟踪会话状态更改。

 如果您拥有关于应用程序行为的专业知识，则可以跳过某些应用程序语句的固定行为。为此，请在创建代理时选择**会话固定筛选条件**选项。当前，您可以选择退出会话固定，以设置会话变量和配置设置。

## 导致对 RDS for PostgreSQL 进行固定的条件
<a name="rds-proxy-pinning.postgres"></a>

 对于 PostgreSQL，以下交互也会导致固定：
+  使用 `SET` 命令。
+  使用 `PREPARE`、`DISCARD`、`DEALLOCATE`、或 `EXECUTE` 命令管理准备好的语句。
+  创建临时序列、表或视图。
+  声明游标。
+  丢弃会话状态。
+  监听通知频道。
+  加载库模块，如 `auto_explain`。
+  使用函数操作序列，例如 `nextval` 和 `setval`。
+  使用函数与锁定交互，例如 `pg_advisory_lock` 和 `pg_try_advisory_lock`。
**注意**  
RDS 代理未锁定事务级咨询锁，特别是 `pg_advisory_xact_lock`、`pg_advisory_xact_lock_shared`、`pg_try_advisory_xact_lock` 和 `pg_try_advisory_xact_lock_shared`。
+ 设置参数或将参数重置为其默认值。具体而言，就是使用 `SET` 和 `set_config` 命令为会话变量分配默认值。
+ 调用存储过程和存储函数不会导致固定。RDS 代理不会检测此类调用导致的任何会话状态更改。如果您希望跨事务持久保持存储例程中的会话状态，请确保您的应用程序不会更改该状态。例如，RDS 代理目前与创建跨所有事务持久存在的临时表的存储过程不兼容。
+ 丢弃会话状态。如果使用连接池库并将 `DISCARD ALL` 查询配置为重置查询，则 RDS 代理会在发布时固定客户端连接。这会降低代理的多路复用效率，并可能导致意想不到的结果，因为 `DISCARD ALL` 命令可能会干扰会话状态管理。