亚马逊AWS官方博客
保驾护航 – Amazon RDS for MySQL 5.7 到 8.0 升级前置检查
1.前言
根据开源 MySQL 官方对 MySQL 5.7 的版本支持信息,首次发布于 2015 年 10 月 21 日的 MySQL 5.7 版本将在 2023 年 10 月 21 日迎来大版本的退役,也表示社区将终止或限制对 MySQL 5.7 版本的支持,以将重点转移到他们的新产品或版本上。鉴于社区版本 EOL 时间在即,没有特殊情况,我们也都会建议客户在处理小版本升级的时候可以实现跨 MySQL 5.7 升级到 Amazon RDS MySQL 8.0 以上版本。所以陆续有越来越多的客户面临着跨版本升级的需求,升级对于客户最关心的几个问题莫过于兼容性、升级影响时间、升级方案、新版本特性等问题。这篇博客主要就 Amazon RDS MySQL 5.7 到 Amazon RDS MySQL 8.0 升级前的兼容性项检查做一个详细的说明和展开。
2.兼容性检查工具
目前 MySQL 官方提供的 MySQL Shell 中有专门用作 MySQL 升级兼容性检查的函数 util.checkForServerUpgrade(),我们可以使用该检查函数在升级之前对相应实例进行初步检查,如果检查中出现升级不兼容项目,输出的日志中会有详细的信息记录,并且会在日志末尾对不兼容项目的数量按照 Error、Warnings 以及 Notices 进行分组统计其数量。对 Amazon RDS 进行实例升级时,升级检查结果记录在 Amazon RDS 的日志记录中,日志文件名为 PrePatchCompatibility.log,当出现直接导致升级失败的错误类型时,也会同时在实例对应 Event 中出现相应的日志记录。
Amazon RDS Event:
Amazon RDS Log:
兼容性检查函数 util.checkForServerUpgrade()会根据目标版本和源版本之间的更改定义兼容性检查项。下面是使用方法以及几种常见的工具使用错误场景。
1)MySQL Shell 升级检查函数 util.checkForServerUpgrade()具体的使用方法如下:
2)使用 MySQL Shell 工具进行前置检查的时候,需选择正确的工具版本。MySQL Shell 8.0.21 及更高版本可用于 RDS 检测,如果版本低于 8.0.21,会出现以下报错:
3)需要注意选择正确版本且保证待检测实例版本与工具版本相匹配。MySQL Shell 默认可检测 8.0.11 至工具版本一致的 MySQL Server 版本。如果选择了与工具版本不相符的实例进行检测,如工具版本为 8.0.21,用来检测 RDS MySQL 5.7.38 版本实例升级至 RDS MySQL 8.0.32 版本会出现以下报错:
如果选择了 RDS MySQL 实例目标版本小于待检测实例的版本,具体报错如下:
该工具检测项目与 RDS 检查项目存在一定的交集,在使用过程中只需关注出错项,部分不适用于 RDS 项不需过多关注,可以使用该工具做一个升级前的不兼容项预检查,以便提前修改不兼容项目。具体的以快照恢复并升级后的测试实例或者实际升级生产实例的输出 PrePatchCompatibility.log 为准。另外,需要注意的是 Amazon RDS MySQL 的 PrePatchCompatibility.log 中检测结果只有 Errors 或者 Warnings 总数的展示,并没有明确标识出哪一项是直接影响升级结果的 Error,哪一项是需要关注但是不直接影响升级结果的 Warning,所以在这篇博客中也将以 Amazon RDS MySQL 的 PrePatchCompatibility.log 实际输出为例做一个常见项具体的展开,以供大家在升级时参考。
3. Amazon RDS for MySQL升级检查结果分析
以版本 5.7.38 到 8.0.32 版本的升级检查项为例,RDS MySQL 一共有 26 项检查,检查结果分 Errors 和 Warnings。其中 Error 项即为可以直接导致升级失败的项目,Warning 则是不会导致升级失败但是需要在升级或后续的使用过程额外关注或修改的项目。接下来会对其中常见的 Error 以及 Warning 项进行详细的展开。
3.1 Error 检查项
以下列示了常见的能直接导致升级失败的检查项,如出现其他导致升级失败的项未列示的情况,可具体分析也可联系作者进一步讨论。以下各项摘取自升级时输出的 PrePatchCompatibility.log。
3.1.1 表包含 5.6.4 之前格式的旧时间列
报错信息
说明
如果表包含 5.6.4 之前格式的旧时间列(TIME、 DATETIME 和 TIMESTAMP 不支持小数秒精度的列),则不支持就地升级到 MySQL 8.0。如果您的表仍然使用旧的临时列格式,请 REPAIR TABLE 在尝试就地升级到 MySQL 8.0 之前使用升级它们。在 5.6.4 之前,datetime 存储占用 8 个字节,而 timestamp 是占用 4 字节;但是在 5.6.4 之后,由于这两个类型允许有小数部分,所以占用的存储空间和以前不同;MySQL 规范规定,datetime 的非小数部分需要 5 个字节,而不是 8 个字节,而 timestamp 的非小数部分是需要 4 个字节,小数部分需要 0 到 3 个字节,具体取决于存储值的小数秒精度。所以如果 RDS MySQL 5.7 中遗留有旧格式的相关字段则会导致升级失败。
失败案例模拟
解决方案
3.1.2 MySQL 系统数据库中不能有与 MySQL 8.0 数据字典中同名的表
报错信息
说明
MySQL 5.7 系统数据库 mysql 中不能有与 MySQL 8.0 数据字典使用的表同名的表。MySQL 8.0 中引入了事务数据字典(DD)支持,为此在 mysql 模式中创建了几个新的 DD 表。因此,在升级之前,应该删除或重命名 mysql 模式中具有冲突名称的用户表。注意 Amazon RDS MySQL 中不允许在 mysql 数据库中自行创建表,所以该模拟场景在开源 MySQL 实例中创建。
失败案例模拟
解决方案
此外,也可以运行如下 SQL 查询在 5.7 中是否有数据字典表名冲突的情况。
3.1.3 不能有使用不支持本地分区的引擎创建分区表
报错信息
说明
官方文档明确支持不能有使用不支持原生分区的存储引擎的分区表。这一项在 MySQL 5.7 中被废弃,在 MySQL 8.0 中被移除,所以分区表使用不支持本地分区引擎的相关表需要在升级之前被修正。
失败案例模拟
解决方案
此外,也可以运行如下 SQL 查询在 5.7 中是否有不支持原生分区的存储引擎的分区表的存在。
对于 Amazon RDS MySQL 需注意,Amazon RDS MySQL 8.0 版本中不允许创建 MyISAM 引擎类表,如创建,会显示 Warning 并自动转为 InnoDB 类表,具体信息如下。在 Amazon RDS MySQL 5.7 版本中可创建。
3.1.4 外键名不能超过 64 字符
报错信息
说明
MySQL 8.0 限制外键名称不能超过 64 个字符。在 8.0 版本之前,如果用户未明确指定外键名称,InnoDB 会自动生成外键约束名称,命名规则为:在表名后附加‘_ibfk_X’(其中 X 是数字)。如果表名本身占用 64 个字符,自动生成的外键约束名称会超过 64 个字符。所以在升级至 MySQL 8.0 版本时,会出现报错。
失败案例模拟
解决方案
可以使用 ALTER TABLE 将其进行修改为不超过 64 字符的外键名。
此外,也可以运行如下 SQL 查询在 5.7 中名称长度超限的外键信息。
3.1.5 表或者存储过程的 ENUM/SET 的所有元素总长度超过 255 字符,会导致升级失败
报错信息
说明
MySQL 8.0 之前,所有枚举元素的总长度可能高达约 64k,因为它存储在 frm 文件中的 2 个字节中,因此表和存储过程可以使用大于 255 个字符的枚举元素创建。在 MySQL 8.0 中,则不支持包含太长枚举文字(即大于 255 个字符)。
失败案例模拟
解决方案
还可以运行以下 SQL 在升级前查询是否有表或者存储过程的 ENUM 或者 SET 的所有元素总长度超过 255 字符。
3.1.6 没有分区表在共享表空间
报错信息
说明
官方文档中明确表示在升级到 MySQL 8.0.13 或更高版本之前,共享 InnoDB 表空间中不能存在表分区,其中包括系统表空间和通用表空间。
失败案例模拟
还可以在升级前运行如下检查 SQL 查询共享 InnoDB 表空间中的表分区。
3.1.7 使用删除的 GROUP BY ASC/DESC 用法(SQL 用法类)
报错信息
说明
该类 SQL 用法在 MySQL 8.0 中已经被移除,使用会直接报错,有相关的存储过程存在,在升级时会直接导致升级失败。
失败案例模拟
解决方案
使用 GROUP BY … ORDER BY … ASC/DESC 代替 ‘GROUP BY with ASC/DESC’。
3.1.8 Issues reported by ‘check table x for upgrade’ command
报错信息
说明
该项检查会输出由’check table x for upgrade’命令检查出的问题,一般是 Error 类问题,需要我们手动处理,如上述 3.1.1 章节旧的时间格式导致的 Error 项以及由于 lower_case_table_names 参数设置在升级前后有变更,导致的表 check 失败的情况,也为 Error 项。因时间格式问题在 3.1.1 章节已做展开,这里不再赘述,而就 lower_case_table_names 变更导致升级失败这一案例进行展开。从 MySQL 8.0.19 开始,如果 lower_case_table_names 设置为 1,升级过程将检查表和架构名称,以确保所有字符均为小写。如果发现表或架构名称包含大写字符,表示在升级前你的实例 lower_case_table_names 设置为 0,那么升级过程将失败并出现错误。
失败案例模拟
解决方案
可以运行以下检查 SQL 提前列出有大小写的对象,并进行 rename 或 drop 操作。
注意 Amazon RDS MySQL 在升级的时候在参数修改这一块做了相应的限制。
3.1.9 mysql.events 列定义中不能出现 NULL 或者空
报错信息
说明
MySQL 创建 event 事件的 definer 列不能为空。
失败案例模拟
解决方案
创建和修改 event 事件的时候,确保 definer 值为非空。如遇到上述报错信息,可以运行以下检查 SQL 列出 definer 列为空的 event 事件,并进行修复。
3.1.10 存在悬空全文索引信息
报错信息
说明
InnoDB 使用称为文档 ID (DOC_ID) 的唯一文档标识符将全文索引中的单词映射到该单词出现的文档记录。该映射需要索引表上的 FTS_DOC_ID 列。如果未定义 FTS_DOC_ID 列,InnoDB 在创建全文索引时会自动添加隐藏的 FTS_DOC_ID 列。当表中添加过全文索引后进行删除,则会有对应的 FTS_DOC_ID 列信息,会导致升级失败。
失败案例模拟
解决方案
还可以运行如下检查语句提前发现悬空全文索引信息。
3.1.11 视图列名不能超过 64 字符
报错信息
说明
在 MySQL 8.0 之前,用户可以创建具有最多 255 个字符的显式列名的视图。为遵守列名的最大长度,MySQL 8.0 不支持显式列名超过 64 个字符的视图。目前这些视图只能通过在 MySQL 5.7 中执行 SHOW CREATE VIEW 来识别。所以在升级至 MySQL 8.0 之前需要修正超长列名,避免升级时候的出错。需要注意的是,这一项在 PrePatchCompatibility 阶段无法检查,但是会导致升级失败,具体的信息可以在 error/mysql-error.log 中查看。
失败案例模拟
解决方案
还可以运行如下检查语句查询对应项,这里需注意大于 64 字符的视图列名在 INFORMATION_SCHEMA.COLUMNS 中会出现截断情况,所以如果升级出现该错误,可进一步检查列名为 64 字符的 VIEW,具体查看 view 定义确认 Error 项。
3.2 Warnings 检查项
不会直接导致升级失败但是在新版本使用前或者使用中需要注意或者修正的检查项。接下来对常见的以下几项进行详细的展开。
3.2.1 新增关键字
警示信息
说明
MySQL 8.0 新增关键字有 cume_dist、dense_rank、empty、except、first_value、grouping、groups、json_table、lag、last_value、lateral、lead、nth_value、ntile、of、over、percent_rank、rank、recursive、row_number、system、window 关键字范围分布在数据库、表、索引、列、alias、view、存储过程、分区、表空间。
为避免使用相关对象的过程中出现问题,在升级前需注意相关对象关键字使用的情况,如有,需要对照使用方法调整代码或存储过程。
案例模拟
解决方案
或者直接加上撇号,键盘数字 1 左边的键。
可以使用如下 SQL 在升级之前进行预检查。
3.2.2 字符集问题
警示信息
说明
MySQL 8.0 默认字符集为 UTF8MB4,MySQL 5.7 默认字符集为 UTF8,MySQL 5.7 使用 UTF8MB3(UTF8) 1-3 字节存储一个字符,MySQL 8.0 默认UTF8MB4 1-4 字节存储一个字符,所以对于列类型的长度的会存在一定的影响,比如 TINYTEXT 最大存储 255 字节,那么可能会出现在 5.7 中最大字符数为 85,8.0 最大字符数则为 63。同样对于索引长度也会有影响,在 REDUNDANT 或者 COMPACT 模式下,最大索引长度为 767 字节,那在 5.7 则允许最长字符字段的索引 255 字符,在 8.0 则是 191 字符。对于升级后未变更字符集的 UTF8 字符类表,如果升级后 character_set_database 设置为默认 utf8mb4,新建表在没有指定 CHARACTER SET 时默认使用 UTF8MB4,当新表和迁移表相关字符字段发生 JOIN 时,会因为 JOIN 两端字段字符集类型不一致导致相关条件字段不能使用索引。
在 Amazon RDS MySQL 8.0 中 UTF8MB3 在表创建的时候会有 Warnings,但是修改还是有一定的代价,需要结合具体使用场景需求决定。且后期 UTF8MB3 会被移除,建议修改 UTF8MB3 类表为 UTF8MB4。
案例模拟
解决方案
也可以使用如下检查 SQL 进行预先检查与发现。
Amazon RDS MySQL 8.0.38 中使用 utf8 会转换 utf8mb3,且 utf8 和 utf8mb3 均会有 Warnings。因为 utf8 这个别名在后续版本中将会成为 utf8mb4 的别名,且 utf8mb3 在后续版本中会移除。且 5.7.38 版本创建表的时候如指定 DEFAULT CHARSET=utf8,该表升级到 8.0.32后,表字符集会自动转换为 CHARSET=utf8mb3。并且在 MySQL8.0 中将不再允许 utf8 这种写法,统一为 utf8mb3。
3.2.3 索引长度不能超过 767 字节
警示信息
说明
在 MySQL 5.5 版本,引入了 innodb_large_prefix,用来禁用大型前缀索引,以便与不支持大索引键前缀的早期版本的 InnoDB 兼容。开启 innodb_large_prefix 可以使单索引的长度限制达到 3072 字节(但是联合索引总长度限制还是 3072 字节),禁用时单索引的长度限制为 767 字节在 MySQL 5.5 版本与 MySQL 5.6 版本,innodb_large_prefix 是默认关闭的,在 MySQL 5.7 及以上版本则默认开启。在 MySQL 8.0 版本中,innodb_large_prefix 已被移除,从版本 8.0 开始,索引长度限制由表字段(row format)决定,若为 DYNAMIC 或 COMPRESSED 时,限制值为 3072;为 REDUNDANT 或 COMPACT 时,限制值为 767。升级时候会检查 REDUNDANT 或 COMPACT 行格式的表升级至 MySQL 8.0 后,表索引长度会超过 767 字节的表。
案例模拟
解决方案
如果表默认字符集保持 MySQL 5.7 中不变,则可以不对该 Warning 进行额外处理。如果需变更表字符集为 utf8mb4,则需要先处理该表索引字段超长问题。可以通过转换表的存储模式来增大限制值。
4.其他未展开项目
除以上常见项,还有以下 13 项仅根据提示修正即可的升级检查项列示如下。如出现且不能根据提示直接解决,可联系作者进一步讨论。
7)Usage of obsolete MAXDB sql_mode flag
8)Usage of obsolete sql_mode flags
11)Circular directory references in tablespace data file paths
12)Usage of removed functions
14)Removed system variables for error logging to the system log configuration
15)Removed system variables
16)System variables with new default values
17)Schema inconsistencies resulting from file removal or corruption
21)Routines with deprecated keywords in definition
22)DB instance must have enough free disk space
23)MySQL preupgrade check to catch users created with MYSQL_NATIVE_PASSWORD plugin
25)The tables with redundant row format can’t have an index larger than 767 bytes.
26)Column definition mismatch between InnoDB Data Dictionary and actual table definition.
5.总结
Amazon RDS for MySQL 5.7 到 8.0 的升级非常重要,其中大版本升级涉及到的兼容性也是用户非常关注的一部分,本篇博客对兼容性检查中常见项目做了具体的展开和说明,并且对可用于兼容性检查工具 MySQL Shell 中的检查函数 util.checkForServerUpgrade()的使用方法以及注意事项作了相关示例,希望能帮助您成功升级 Amazon RDS for MySQL 5.7 到 8.0。
系列博客
- 保驾护航 – Amazon RDS for MySQL 5.7 到 8.0 升级指南
- 保驾护航 – Amazon RDS for MySQL 5.7 到 8.0 升级前置检查(本篇)
- 保驾护航 – Amazon RDS for MySQL 5.7 到 8.0 升级方案
- 保驾护航 – 实战分享,通过 External Master 完成 Amazon RDS for MySQL 加密和升级
- 保驾护航 – Amazon RDS for MySQL 5.7 到 8.0 升级优势
- 保驾护航:手工搭建 Amazon RDS mysql 5.7/8.0 跨账号的迁移或容灾