

# MySQL 数据库实例的数据库管理员常见任务
<a name="Appendix.MySQL.CommonDBATasks"></a>

您可以在下面的内容中找到一些常见数据管理员任务的 Amazon RDS 特定实施描述，这些任务适用于运行 MySQL 数据库引擎的数据库实例。为了提供托管服务体验，Amazon RDS 未提供数据库实例的 Shell 访问权限。并且它还限制了对需要高级权限的某些系统程序和表的访问。

有关在 Amazon RDS 上使用 MySQL 日志文件的信息，请参阅 [MySQL 数据库日志文件](USER_LogAccess.Concepts.MySQL.md)。

## 了解预定义用户
<a name="Appendix.MySQL.CommonDBATasks.users"></a>

Amazon RDS 使用新的 RDS for MySQL 数据库实例自动创建若干预定义用户。无法更改预定义用户及其权限。无法删除、重命名或修改这些预定义用户的权限。此类尝试会导致错误。
+ **rdsadmin** – 具有 `superuser` 权限的管理员将对独立的 PostgreSQL 数据库执行许多管理任务，此用户专为处理这些管理任务而创建。此用户供 RDS for MySQL 在内部执行许多管理任务。
+ **rdsrepladmin** - Amazon RDS 在内部使用的用户，用于支持 RDS for MySQL 数据库实例和集群上的复制活动。

有关其它常见 DBA 任务的信息，请参阅以下主题。

**Topics**
+ [了解预定义用户](#Appendix.MySQL.CommonDBATasks.users)
+ [RDS for MySQL 的基于角色的权限模型](Appendix.MySQL.CommonDBATasks.privilege-model.md)
+ [适用于 RDS for MySQL 的动态权限](Appendix.MySQL.CommonDBATasks.dynamic-privileges.md)
+ [结束 RDS for MySQL 的会话或查询](Appendix.MySQL.CommonDBATasks.End.md)
+ [跳过 RDS for MySQL 的当前复制错误](Appendix.MySQL.CommonDBATasks.SkipError.md)
+ [使用 InnoDB 表空间改善 RDS for MySQL 的崩溃恢复时间](Appendix.MySQL.CommonDBATasks.Tables.md)
+ [管理 RDS for MySQL 的全局状态历史记录](Appendix.MySQL.CommonDBATasks.GoSH.md)
+ [在 MySQL 8.4 中配置缓冲池大小和重做日志容量](Appendix.MySQL.CommonDBATasks.Config.Size.8.4.md)

# RDS for MySQL 的基于角色的权限模型
<a name="Appendix.MySQL.CommonDBATasks.privilege-model"></a>

从 RDS for MySQL 版本 8.0.36 开始，您无法直接修改 `mysql` 数据库中的表。特别是，您不能通过对 `grant` 表执行数据操作语言（DML）操作来创建数据库用户。相反，您可以使用 MySQL 账户管理语句（例如 `CREATE USER`、`GRANT`、和 `REVOKE`）向用户授予基于角色的权限。您也无法创建其他类型的对象，例如 `mysql` 数据库中的存储过程。您仍然可以查询 `mysql` 表。如果您使用二进制日志复制，则直接对源数据库实例上的 `mysql` 表进行的更改不会复制到目标集群中。

在某些情况下，您的应用程序可能会使用快捷方式通过插入到 `mysql` 表来创建用户或其他对象。如果是这样，请更改应用程序代码以使用相应的语句，例如 `CREATE USER`。

要在从外部 MySQL 数据库迁移期间导出数据库用户的元数据，请使用以下方法之一：
+ 将 MySQL Shell 的实例转储实用程序与筛选条件一起使用，来排除用户、角色和授权。以下示例显示了要使用的命令语法。确保 `outputUrl` 为空。

  ```
  mysqlsh user@host -- util.dumpInstance(outputUrl,{excludeSchemas:['mysql'],users: true})
  ```

  有关更多信息，请参阅《MySQL 参考手册》中的 [Instance Dump Utility, Schema Dump Utility, and Table Dump Utility](https://dev.mysql.com/doc/mysql-shell/8.0/en/mysql-shell-utilities-dump-instance-schema.html)。
+ 使用 `mysqlpump` 客户端实用程序。此示例包括除 `mysql` 系统数据库中的表之外的所有表。它还包括用于重现迁移数据库中的所有 MySQL 用户的 `CREATE USER` 和 `GRANT` 语句。

  ```
  mysqlpump --exclude-databases=mysql --users
  ```

  MySQL 8.4 中不再提供 `mysqlpump` 客户端实用工具。请改用`mysqldump`。

为了简化对许多用户或应用程序的权限管理，您可以使用 `CREATE ROLE` 语句来创建具有一组权限的角色。然后，您可以使用 `GRANT` 和 `SET ROLE` 语句以及 `current_role` 函数将角色分配给用户或应用程序、切换当前角色以及检查哪些角色有效。有关 MySQL 8.0 中基于角色的权限系统的更多信息，请参阅 MySQL 参考手册中的[使用角色](https://dev.mysql.com/doc/refman/8.0/en/roles.html)。

**重要**  
我们强烈建议不要直接在应用程序中使用主用户。请遵守使用数据库用户的最佳实践，按照您的应用程序所需的最少权限创建用户。

从版本 8.0.36 开始，RDS for MySQL 包括一个具有以下所有权限的特殊角色。该角色命名为 `rds_superuser_role`。每个数据库实例的主管理用户已经获得了此角色。`rds_superuser_role` 角色包括所有数据库对象的以下权限：
+  `ALTER` 
+  `APPLICATION_PASSWORD_ADMIN` 
+  `ALTER ROUTINE` 
+  `CREATE` 
+  `CREATE ROLE` 
+  `CREATE ROUTINE` 
+  `CREATE TEMPORARY TABLES` 
+  `CREATE USER` 
+  `CREATE VIEW` 
+  `DELETE` 
+  `DROP` 
+  `DROP ROLE` 
+  `EVENT` 
+  `EXECUTE` 
+  `INDEX` 
+  `INSERT` 
+  `LOCK TABLES` 
+  `PROCESS` 
+  `REFERENCES` 
+  `RELOAD` 
+  `REPLICATION CLIENT` 
+  `REPLICATION SLAVE` 
+  `ROLE_ADMIN` 
+  `SET_USER_ID` 
+  `SELECT` 
+  `SHOW DATABASES` 
+  `SHOW VIEW` 
+  `TRIGGER` 
+  `UPDATE` 
+  `XA_RECOVER_ADMIN`

 角色定义还包括 `WITH GRANT OPTION`，以便管理用户可以将该角色授予其他用户。特别是，管理员必须授予以 MySQL 集群作为目标执行二进制日志复制所需的任何权限。

**提示**  
 要查看权限的完整详细信息，请使用以下语句。  

```
SHOW GRANTS FOR rds_superuser_role@'%';
```

 当您使用 RDS for MySQL 版本 8.0.36 和更高版本中的角色授予访问权限时，还可以通过使用 `SET ROLE role_name` 或 `SET ROLE ALL` 语句来激活角色。下面的示例演示如何操作。将适当的角色名称替换为 `CUSTOM_ROLE`。

```
# Grant role to user
mysql> GRANT CUSTOM_ROLE TO 'user'@'domain-or-ip-address'

# Check the current roles for your user. In this case, the CUSTOM_ROLE role has not been activated.
# Only the rds_superuser_role is currently in effect.
mysql> SELECT CURRENT_ROLE();
+--------------------------+
| CURRENT_ROLE()           |
+--------------------------+
| `rds_superuser_role`@`%` |
+--------------------------+
1 row in set (0.00 sec)

# Activate all roles associated with this user using SET ROLE.
# You can activate specific roles or all roles.
# In this case, the user only has 2 roles, so we specify ALL.
mysql> SET ROLE ALL;
Query OK, 0 rows affected (0.00 sec)

# Verify role is now active
mysql> SELECT CURRENT_ROLE();
+--------------------------------------------------+
| CURRENT_ROLE()                                   |
+--------------------------------------------------+
| `CUSTOM_ROLE`@`%`,`rds_superuser_role`@`%` |
+--------------------------------------------------+
```

# 适用于 RDS for MySQL 的动态权限
<a name="Appendix.MySQL.CommonDBATasks.dynamic-privileges"></a>

动态权限是可以使用 `GRANT` 语句显式授予的 MySQL 权限。根据 RDS for MySQL 版本，RDS 支持您仅授予特定的动态权限。RDS 不支持使用其中某些权限，因为这些权限可能会干扰特定的数据库操作，例如复制和备份。

下表显示了可以针对不同的 MySQL 版本授予其中哪些权限。如果要从低于 8.0.36 的 MySQL 版本升级到 8.0.36 或更高版本，则当不再支持授予特定权限时，可能需要更新应用程序代码。


| 特权 | MySQL 8.0.35 及更低版本 | MySQL 8.0.36 及更高的次要版本 | MySQL 8.4.3 及更高版本 | 
| --- | --- | --- | --- | 
|  [ALLOW\$1NONEXISTENT\$1DEFINER](https://dev.mysql.com/doc/refman/8.4/en/privileges-provided.html#priv_allow-nonexistent-definer)   |  不可用  |  不可用  |  不允许  | 
|  [APPLICATION\$1PASSWORD\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_application-password-admin)  |  已允许  |  已允许  |  已允许  | 
|  [AUDIT\$1ABORT\$1EXEMPT](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_audit-abort-exempt)  |  已允许  |  不允许  |  不允许  | 
|  [AUDIT\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_audit-admin)  |  不允许  |  不允许  |  不允许  | 
|  [AUTHENTICATION\$1POLICY\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_authentication-policy-admin)  |  已允许  |  不允许  | 不允许 | 
|  [BACKUP\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_backup-admin)  |  已允许  |  不允许  |  不允许  | 
|  [BINLOG\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_binlog-admin)  |  已允许  |  不允许  |  不允许  | 
|  [BINLOG\$1ENCRYPTION\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_binlog-encryption-admin)  |  不允许  |  不允许  |  不允许  | 
|  [CLONE\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_clone-admin)  |  不允许  |  不允许  |  不允许  | 
|  [CONNECTION\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_connection-admin)  |  已允许  |  不允许  |  不允许  | 
|  [ENCRYPTION\$1KEY\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_encryption-key-admin)  |  不允许  |  不允许  |  不允许  | 
|  [FIREWALL\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_firewall-admin)  |  不允许  |  不允许  |  不允许  | 
|  [FIREWALL\$1EXEMPT](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_firewall-exempt)  |  已允许  |  不允许  |  不允许  | 
|  [FIREWALL\$1USER](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_firewall-user)  |  不允许  |  不允许  |  不允许  | 
|  [FLUSH\$1OPTIMIZER\$1COSTS](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_flush-optimizer-costs)  |  已允许  |  已允许  |  已允许  | 
|  [FLUSH\$1PRIVILEGES](https://dev.mysql.com/doc/refman/8.4/en/privileges-provided.html#priv_flush-privileges)  |  不可用  |  不可用  |  已允许  | 
|  [FLUSH\$1STATUS](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_flush-status)  |  已允许  |  已允许  |  已允许  | 
|  [FLUSH\$1TABLES](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_flush-tables)  |  已允许  |  已允许  |  已允许  | 
|  [FLUSH\$1USER\$1RESOURCES](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_flush-user-resources)  |  已允许  |  已允许  |  已允许  | 
|  [GROUP\$1REPLICATION\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_group-replication-admin)  |  不允许  |  不允许  |  不允许  | 
|  [GROUP\$1REPLICATION\$1STREAM](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_group-replication-stream)  |  不允许  |  不允许  |  不允许  | 
|  [INNODB\$1REDO\$1LOG\$1ARCHIVE](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_innodb-redo-log-archive)  |  不允许  |  不允许  |  不允许  | 
|  [INNODB\$1REDO\$1LOG\$1ENABLE](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_innodb-redo-log-enable)  |  不允许  |  不允许  |  不允许  | 
|  [MASKING\$1DICTIONARIES\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_masking-dictionaries-admin)  |  不允许  |  不允许  |  不允许  | 
|  [NDB\$1STORED\$1USER](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_ndb-stored-user)  |  不允许  |  不允许  |  不允许  | 
|  [OPTIMIZE\$1LOCAL\$1TABLE](https://dev.mysql.com/doc/refman/8.4/en/privileges-provided.html#priv_optimize-local-table)  |  不可用  |  不可用  |  不允许  | 
|  [PASSWORDLESS\$1USER\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_passwordless-user-admin)  |  不允许  |  不允许  |  不允许  | 
|  [PERSIST\$1RO\$1VARIABLES\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_persist-ro-variables-admin)  |  不允许  |  不允许  |  不允许  | 
|  [REPLICATION\$1APPLIER](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_replication-applier)  |  已允许  |  不允许  |  不允许  | 
|  [REPLICATION\$1SLAVE\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_replication-slave-admin)  |  不允许  |  不允许  |  不允许  | 
|  [RESOURCE\$1GROUP\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_resource-group-admin)  |  已允许  |  不允许  |  不允许  | 
|  [RESOURCE\$1GROUP\$1USER](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_resource-group-user)  |  已允许  |  不允许  |  不允许  | 
|  [ROLE\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_role-admin)  |  已允许  |  已允许  |  已允许  | 
|  [SENSITIVE\$1VARIABLES\$1OBSERVER](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_sensitive-variables-observer)  |  已允许  |  已允许  | 已允许 | 
|  [SERVICE\$1CONNECTION\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_service-connection-admin)  |  已允许  |  不允许  |  不允许  | 
|  [SESSION\$1VARIABLES\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_session-variables-admin)  |  已允许  |  已允许  |  已允许  | 
|  [SET\$1ANY\$1DEFINER](https://dev.mysql.com/doc/refman/8.4/en/privileges-provided.html#priv_set-any-definer)  |  不可用  |  不可用  |  已允许  | 
|  [SET\$1USER\$1ID](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_set-user-id)  |  已允许  |  已允许  |  不可用  | 
|  [SHOW\$1ROUTINE](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_show-routine)  |  已允许  |  已允许  |  已允许  | 
|  [SKIP\$1QUERY\$1REWRITE](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_skip-query-rewrite)  |  不允许  |  不允许  |  不允许  | 
|  [SYSTEM\$1USER](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_system-user)  |  不允许  |  不允许  |  不允许  | 
|  [SYSTEM\$1VARIABLES\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_system-variables-admin)  |  不允许  |  不允许  |  不允许  | 
|  [TABLE\$1ENCRYPTION\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_table-encryption-admin)  |  不允许  |  不允许  |  不允许  | 
|  [TELEMETRY\$1LOG\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_telemetry-log-admin)  |  已允许  |  不允许  |  不允许  | 
|  [TP\$1CONNECTION\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_tp-connection-admin)  |  不允许  |  不允许  | 不允许 | 
|  [TRANSACTION\$1GTID\$1TAG](https://dev.mysql.com/doc/refman/8.4/en/privileges-provided.html#priv_transaction-gtid-tag)   |  不可用  |  不可用  | 不允许 | 
|  [VERSION\$1TOKEN\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_version-token-admin)  |  不允许  |  不允许  |  不允许  | 
|  [XA\$1RECOVER\$1ADMIN](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_xa-recover-admin)  |  已允许  |  已允许  |  已允许  | 

# 结束 RDS for MySQL 的会话或查询
<a name="Appendix.MySQL.CommonDBATasks.End"></a>

您可使用 `rds_kill` 和 `rds_kill_query` 命令结束数据库实例上的用户会话或查询。首先连接到 MySQL 数据库实例，然后发出正确的命令，如下所示。有关更多信息，请参阅“[连接到 MySQL 数据库实例](USER_ConnectToInstance.md)”。

```
CALL mysql.rds_kill(thread-ID)
CALL mysql.rds_kill_query(thread-ID)
```

例如，要结束线程 99 上运行的会话，可以键入以下内容：

```
CALL mysql.rds_kill(99); 
```

要结束线程 99 上运行的查询，可以键入以下内容：

```
CALL mysql.rds_kill_query(99); 
```

# 跳过 RDS for MySQL 的当前复制错误
<a name="Appendix.MySQL.CommonDBATasks.SkipError"></a>

如果错误导致只读副本停止响应但不影响数据的完整性，您可以跳过只读副本错误。

**注意**  
请先验证是否可以安全地跳过错误。在 MySQL 实用工具中，连接到只读副本并运行以下 MySQL 命令。  

```
SHOW REPLICA STATUS\G 
```
有关返回值的信息，请参阅 [MySQL 文档](https://dev.mysql.com/doc/refman/8.0/en/show-replica-status.html)。  
以前的 MySQL 版本使用的是 `SHOW SLAVE STATUS` 而不是 `SHOW REPLICA STATUS`。如果您使用的 MySQL 版本低于 8.0.23，那么请使用 `SHOW SLAVE STATUS`。

您可以通过以下方式跳过只读副本上的错误。

**Topics**
+ [调用 mysql.rds\$1skip\$1repl\$1error 过程](#Appendix.MySQL.CommonDBATasks.SkipError.procedure)
+ [设置 slave\$1skip\$1errors 参数](#Appendix.MySQL.CommonDBATasks.SkipError.parameter)

## 调用 mysql.rds\$1skip\$1repl\$1error 过程
<a name="Appendix.MySQL.CommonDBATasks.SkipError.procedure"></a>

Amazon RDS 提供了一个存储过程，您可以调用该过程以跳过只读副本上的错误。首先连接到您的只读副本，然后发出正确的命令，如下所示。有关更多信息，请参阅 [连接到 MySQL 数据库实例](USER_ConnectToInstance.md)。

 要跳过错误，请发出以下命令。

```
CALL mysql.rds_skip_repl_error; 
```

如果您在未遇到复制错误的源数据库实例或只读副本上运行此命令，则此命令不会产生任何影响。

有关更多信息 (如支持 `mysql.rds_skip_repl_error` 的 MySQL 版本)，请参阅 [mysql.rds\$1skip\$1repl\$1error](mysql-stored-proc-replicating.md#mysql_rds_skip_repl_error)。

**重要**  
如果您尝试调用 `mysql.rds_skip_repl_error` 并遇到以下错误：`ERROR 1305 (42000): PROCEDURE mysql.rds_skip_repl_error does not exist`，请将您的 MySQL 数据库实例升级到最新次要版本或是 [mysql.rds\$1skip\$1repl\$1error](mysql-stored-proc-replicating.md#mysql_rds_skip_repl_error) 中列出的最低次要版本之一。

## 设置 slave\$1skip\$1errors 参数
<a name="Appendix.MySQL.CommonDBATasks.SkipError.parameter"></a>

要跳过一个或多个错误，您可以设置在只读副本上设置 `slave_skip_errors` 静态参数。您可以将此参数设置为跳过一个或多个特定的复制错误代码。目前，您只能为适用于 MySQL 5.7 的 RDS 数据库实例设置此参数。更改此参数的设置后，确保重启数据库实例，以使新设置生效。有关设置此参数的信息，请参阅 [MySQL 文档](https://dev.mysql.com/doc/refman/5.7/en/replication-options-replica.html#sysvar_slave_skip_errors)。

我们建议在单独的数据库参数组中设置此参数。您只能将此数据库参数组与需要跳过错误的只读副本关联。遵循此最佳实践可以减少对其他数据库实例和只读副本的潜在影响。

**重要**  
为此参数设置非默认值可能会导致复制不一致。只有在用尽其他选项来解决问题并且确定对只读副本数据的潜在影响时，才将此参数设置为非默认值。

# 使用 InnoDB 表空间改善 RDS for MySQL 的崩溃恢复时间
<a name="Appendix.MySQL.CommonDBATasks.Tables"></a>

MySQL 中的所有表均由表定义、数据和索引组成。MySQL 存储引擎 InnoDB 将表数据和索引存储在*表空间*中。InnoDB 创建全局共享的表空间，其中包括数据字典和其他相关元数据，并且它可能包含表数据和索引。InnoDB 还可以为每张表创建单独的表空间和分区。这些单独的表空间存储在后缀名为 .ibd 的文件中，并且每个表空间的头部包含一个唯一识别编号。

`innodb_file_per_table` 提供一个属于 MySQL 参数组的参数，名称为 Amazon RDS。这些参数控制 InnoDB 是否（通过将参数值设置为 0）向共享表空间或（通过将参数值设置为 1）向单个表空间添加新的表数据和索引。Amazon RDS 将 `innodb_file_per_table` 参数的默认值设置为 1，以便删除单独的 InnoDB 表并回收数据库实例的表所占用的存储空间。在大多数使用案例中，推荐将 `innodb_file_per_table` 参数设置为 1。

当表特别多时 (例如，当使用标准 (磁性) 或通用 SSD 存储时，有超过 1000 张表，或当使用预置的 IOPS 存储时，有超过 10000 张表)，应将 `innodb_file_per_table` 参数设置为 0。当将该参数设置为 0 时，不会创建独立表空间，这样可以节省数据库崩溃恢复所需的时间。

MySQL 在崩溃恢复循环期间处理每个元数据文件 (包括表空间)。当有多个表空间时，与 MySQL 用于处理数以千计的表空间文件的时间相比，MySQL 用于处理共享表空间中的元数据信息的时间可以忽略不计。因为表空间编号存储在每个文件的头部，读取所有表空间文件的总时间可能需要长达数小时。例如，在崩溃恢复循环期间，标准存储空间上的一百万个 InnoDB 表空间可能需要 5 到 8 个小时的处理时间。在一些案例中，InnoDB 可能会在一个崩溃恢复循环后确定它需要额外清理，因此，它会开始另一个崩溃恢复循环，这会使恢复时间延长。请记住，崩溃恢复循环也会引起回滚事务、修复损坏页面和除表空间信息处理以外的其他操作。

因为 `innodb_file_per_table` 参数存储在参数组中，所以可通过编辑数据库实例所使用的参数组来更改该参数值，无需重新启动该数据库实例。更改该设置后，例如从 1 (创建独立的表) 改为 0 (使用共享的表空间)，新的 InnoDB 表将添加到共享的表空间，而现有的表继续使用独立的表空间。要将 InnoDB 表移动到共享的表空间，必须使用 `ALTER TABLE` 命令。

## 将多个表空间迁移到共享的表空间
<a name="Appendix.MySQL.CommonDBATasks.MigrateMultiTbs"></a>

您可将 InnoDB 表的元数据从其自己的表空间移至共享的表空间，这将按照 `innodb_file_per_table` 参数设置重建表的元数据。首先连接到 MySQL 数据库实例，然后发出正确的命令，如下所示。有关更多信息，请参阅“[连接到 MySQL 数据库实例](USER_ConnectToInstance.md)”。

```
ALTER TABLE table_name ENGINE = InnoDB, ALGORITHM=COPY; 
```

例如，以下查询为不在共享表空间中的每个 InnoDB 表返回 `ALTER TABLE` 语句。

**对于 MySQL 5.7 数据库实例：**

```
SELECT CONCAT('ALTER TABLE `', 
REPLACE(LEFT(NAME , INSTR((NAME), '/') - 1), '`', '``'), '`.`', 
REPLACE(SUBSTR(NAME FROM INSTR(NAME, '/') + 1), '`', '``'), '` ENGINE=InnoDB, ALGORITHM=COPY;') AS Query 
FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES 
WHERE SPACE <> 0 AND LEFT(NAME, INSTR((NAME), '/') - 1) NOT IN ('mysql','');
```

**对于 MySQL 8.4 和 8.0 数据库实例：**

```
SELECT CONCAT('ALTER TABLE `', 
REPLACE(LEFT(NAME , INSTR((NAME), '/') - 1), '`', '``'), '`.`', 
REPLACE(SUBSTR(NAME FROM INSTR(NAME, '/') + 1), '`', '``'), '` ENGINE=InnoDB, ALGORITHM=COPY;') AS Query 
FROM INFORMATION_SCHEMA.INNODB_TABLES 
WHERE SPACE <> 0 AND LEFT(NAME, INSTR((NAME), '/') - 1) NOT IN ('mysql','');
```

重建一个 MySQL 表以便将该表的元数据移动到共享的表空间，这需要额外的临时存储空间以重建该表，因此，该数据库实例必须有可用的存储空间。在重建期间，该表会被锁定，无法访问查询。对于不经常访问的小型表或普通表，这可能不是问题。对于在大量并发环境中经常访问的大型表或普通表，您可以在只读副本上重建表。

您可以创建只读副本，并将表元数据迁移到只读副本上的共享表空间。虽然 ALTER TABLE 语句会阻止访问只读副本，但源数据库实例不会受到影响。尽管只读副本会在表重建过程中滞后，但源数据库实例将继续生成其二进制日志。由于重建需要额外的存储空间，并且重放日志文件可能会变得很大，因此，您应该创建只读副本，并向其分配大于源数据库实例的存储空间。

要创建只读副本和重建 InnoDB 表以便使用共享表空间，请遵循以下步骤：

1. 确保在源数据库实例上启用备份保留，以便启用二进制日志记录。

1. 使用 AWS 管理控制台或 AWS CLI 创建源数据库实例的只读副本。由于创建只读副本涉及的流程与崩溃恢复一样多，因此，如果存在大量 InnoDB 表空间，创建过程可能会需要一些时间。在只读副本上分配的存储空间应大于源数据库实例上当前使用的空间。

1. 创建只读副本后，使用参数设置 `read_only = 0` 和 `innodb_file_per_table = 0` 创建参数组，然后将该参数组与只读副本关联。

1. 针对您要在副本中迁移的所有表发出以下 SQL 语句。

   ```
   ALTER TABLE name ENGINE = InnoDB
   ```

1. 在只读副本中完成所有 `ALTER TABLE` 语句后，验证只读副本是否连接至源数据库实例，并且两个实例是否同步。

1. 使用控制台或 CLI 将只读副本提升为实例。确保用于新的独立数据库实例的参数组已将 `innodb_file_per_table` 参数设置为 0。更改新的独立数据库实例的名称，并将所有应用程序指向新的独立数据库实例。

# 管理 RDS for MySQL 的全局状态历史记录
<a name="Appendix.MySQL.CommonDBATasks.GoSH"></a>

**提示**  
要分析数据库性能，您还可以在 Amazon RDS 上使用性能详情。有关更多信息，请参阅 [在 Amazon RDS 上使用性能详情监控数据库负载](USER_PerfInsights.md)。

MySQL 保存了很多状态变量，用于提供与操作相关的信息。状态变量值可以帮助您检测数据库实例上的锁定或内存问题。这些状态变量的值会从上次启动数据库实例时开始累积。可以使用 `FLUSH STATUS` 命令将大多数状态变量重置为 0。

Amazon RDS 提供了一套程序，这些程序会随着时间为这些状态变量的值创建快照，并将它们及上次创建快照后所做的任何更改写入一个表中，从而可以随时间监控这些值。此基础设施名为 Global Status History (GoSH)，安装在从版本 5.5.23 开始的所有 MySQL 数据库实例上。默认情况下 GoSH 处于禁用状态。

要启用 GoSH，请首先在数据库参数组中通过将参数 `event_scheduler` 设置为 `ON`，启用事件调度器。对于运行 MySQL 5.7 的 MySQL 数据库实例，还要将参数 `show_compatibility_56` 设置为 `1`。有关创建和修改数据库参数组的信息，请参阅 [Amazon RDS 的参数组](USER_WorkingWithParamGroups.md)。有关启用此参数的副作用的信息，请参阅《MySQL 5.7 参考手册》**中的 [show\$1compatibility\$156](https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_show_compatibility_56)。

然后可以使用下表中的程序启用和配置 GoSH。首先连接到 MySQL 数据库实例，然后发出正确的命令，如下所示。有关更多信息，请参阅 [连接到 MySQL 数据库实例](USER_ConnectToInstance.md)。对于每个过程，运行以下命令并替换 **procedure-name**：

```
CALL procedure-name; 
```

下表列出了可用于上一个命令中 **procedure-name** 的所有过程。


| 程序 | 描述 | 
| --- | --- | 
| `mysql.rds_enable_gsh_collector` |  启用 GoSH，按照 `rds_set_gsh_collector` 指定的间隔创建默认快照。  | 
| `mysql.rds_set_gsh_collector` |  指定快照之间的间隔，以分钟为单位。默认值是 5。  | 
| `mysql.rds_disable_gsh_collector` |  禁用快照。  | 
| `mysql.rds_collect_global_status_history` |  根据需求创建快照。  | 
| `mysql.rds_enable_gsh_rotation` |  按照 `mysql.rds_global_status_history` 指定的间隔，使 `mysql.rds_global_status_history_old` 表的内容可交替到 `rds_set_gsh_rotation`。  | 
| `mysql.rds_set_gsh_rotation` |  指定表交替之间的间隔，以天为单位。默认值是 7。  | 
| `mysql.rds_disable_gsh_rotation` |  禁用表交替。  | 
| `mysql.rds_rotate_global_status_history` |  根据需求将 `mysql.rds_global_status_history` 表的内容交替到 `mysql.rds_global_status_history_old`。  | 

GoSH 运行时，您可以查询 GoSH 要写入的表。例如，要查询 Innodb 缓冲池的命中率，您可以发送以下查询请求：

```
select a.collection_end, a.collection_start, (( a.variable_Delta-b.variable_delta)/a.variable_delta)*100 as "HitRatio" 
    from mysql.rds_global_status_history as a join mysql.rds_global_status_history as b on a.collection_end = b.collection_end
    where a. variable_name = 'Innodb_buffer_pool_read_requests' and b.variable_name = 'Innodb_buffer_pool_reads'
```

# 在 MySQL 8.4 中配置缓冲池大小和重做日志容量
<a name="Appendix.MySQL.CommonDBATasks.Config.Size.8.4"></a>

在 MySQL 8.4 中，Amazon RDS 默认启用 `innodb_dedicated_server` 参数。使用 `innodb_dedicated_server` 参数，数据库引擎可计算 `innodb_buffer_pool_size` 和 `innodb_redo_log_capacity` 参数。有关如何计算这些参数的信息，请参阅 MySQL 文档中的 [Configuring InnoDB Buffer Pool Size](https://dev.mysql.com/doc/refman/8.4/en/innodb-buffer-pool-resize.html) 和 [Redo Log](https://dev.mysql.com/doc/refman/8.4/en/innodb-redo-log.html)。

启用 `innodb_dedicated_server` 后，将根据数据库实例类内存计算 `innodb_buffer_pool_size` 参数。下表显示了检测到的服务器内存和相应的缓冲池大小。


| 检测到的服务器内存 | 缓冲池大小 | 
| --- | --- | 
|  < 1 GB  |  默认值为 128 MB  | 
|  1 GB 到 4 GB  |  *检测到的服务器内存* \$1 0.5  | 
|  > 4 GB  |  *检测到的服务器内存* \$1 0.75  | 

`innodb_redo_log_capacity` 参数会随实例类自动扩展到（vCPU 数量 / 2）GB，最大可达 16 GB。较大的实例类具有更大的重做日志容量，这样可以提高写入密集型工作负载的性能和弹性。

从 MySQL 8.0 升级到 MySQL 8.4 之前，请务必增加存储空间，以适应升级完成后可能出现的重做日志大小的增加。有关更多信息，请参阅 [增加数据库实例存储容量](USER_PIOPS.ModifyingExisting.md)。

如果您不希望 `innodb_dedicated_server` 参数计算 `innodb_buffer_pool_size` 和 `innodb_redo_log_capacity` 参数的值，则可以通过在自定义参数组中为这些值设置特定值来覆盖这些值。或者，您可以禁用 `innodb_dedicated_server` 参数，并在自定义参数组中设置 `innodb_buffer_pool_size` 和 `innodb_redo_log_capacity` 参数的值。有关更多信息，请参阅 [原定设置和自定义参数组](parameter-groups-overview.md#parameter-groups-overview.custom)。

如果您通过将 `innodb_dedicated_server` 参数设置为 `0` 来禁用该参数，并且未为 `innodb_buffer_pool_size` 和 `innodb_redo_log_capacity` 参数设置值，则 Amazon RDS 会将后两个参数分别设置为 128 MB 和 100 MB。这些默认值会导致在较大的实例类上性能不佳。