文档中心>云数据库 MySQL>操作指南>升级实例>MySQL 5.7升级 MySQL 8.0预检查及问题修复指南

MySQL 5.7升级 MySQL 8.0预检查及问题修复指南

最近更新时间:2026-01-06 14:25:32

我的收藏

目录

附录

一、InnoDB 内部结构检查

1.1 旧时间类型格式(oldTemporalCheck)

错误信息:Usage of old temporal type
错误级别:ERROR。

错误原因

MySQL 5.5及更早版本使用了一种旧的时间类型磁盘存储格式。这种格式在 MySQL 8.0中已不再支持,必须在升级前转换为新格式。

技术背景

问题点
说明
影响的数据类型
TIME,DATETIME,TIMESTAMP
旧格式特征
列类型显示包含 "5.5 binary format"
为何不兼容
MySQL 8.0完全移除了对旧时间格式的支持

检测方法

SELECT table_schema, table_name, column_name, column_type
FROM information_schema.columns
WHERE column_type LIKE '%5.5 binary format%';

解决方案

-- 对检测到的每张表执行重建
ALTER TABLE 数据库名.表名 FORCE;

1.2 Schema 不一致检查(schemaInconsistencyCheck)

错误信息:Schema inconsistencies resulting from file removal or corruption
错误级别:ERROR。

错误原因

表的数据文件(.ibd)或元数据文件(.frm)被意外删除或损坏,导致 InnoDB 数据字典与 MySQL 元数据不一致。

技术背景

问题点
说明
常见原因
手动删除数据文件、磁盘故障、文件系统错误
表现形式
表存在于 InnoDB 数据字典但不在 information_schema.tables 中
升级影响
MySQL 8.0的新数据字典无法正确迁移这些不一致的表

检测方法

-- 查找存在于 InnoDB 但不在 TABLES 表中的记录
SELECT t.NAME as table_name
FROM information_schema.innodb_sys_tables t
LEFT JOIN information_schema.tables it
ON CONCAT(it.TABLE_SCHEMA, '/', it.TABLE_NAME) = t.NAME
WHERE it.TABLE_NAME IS NULL
AND t.NAME NOT LIKE 'SYS_%'
AND t.NAME NOT LIKE 'mysql/%';

解决方案

1. 检查错误日志:
grep -i "corrupt\\|missing\\|error" /var/log/mysql/error.log
2. 检查数据目录:
ls -la /var/lib/mysql/数据库名/
3. 修复方案(根据情况选择):
-- 如果表确实不需要,清理 InnoDB 数据字典
-- 需要创建同名空表后删除
CREATE TABLE 数据库名.表名 (id INT) ENGINE=InnoDB;
DROP TABLE 数据库名.表名;

-- 如果需要恢复数据,尝试从备份恢复

1.3 旧几何类型检查(oldGeometryCheck)

错误信息:Spatial data columns created in MySQL 5.6
错误级别:ERROR(不适用于 8.0.24+)。

错误原因

在 MySQL 5.6中创建的空间数据列使用了旧的存储格式,8.0.24之前的 MySQL 8.0版本不支持直接升级这些表。

技术背景

问题点
说明
影响的数据类型
POINT,GEOMETRY,POLYGON,LINESTRING,MULTIPOINT,MULTILINESTRING,MULTIPOLYGON,GEOMETRYCOLLECTION
版本限制
8.0.24之前的版本无法升级这些表
推荐方案
直接升级到8.0.24或更新的版本

解决方案

方案一:直接升级到 MySQL 8.0.24+(推荐)
社区版本和云数据库 MySQL 内核版本的对应关系可参见 TXSQL 引擎内核版本更新动态,升级云数据库 MySQL 内核版本的操作请参见 升级内核小版本
方案二:升级前重建受影响的表
-- 查找受影响的表
SELECT table_schema, table_name, column_name, data_type
FROM information_schema.columns
WHERE data_type IN ('point', 'geometry', 'polygon', 'linestring',
'multipoint', 'multilinestring', 'multipolygon',
'geometrycollection');

-- 重建表
ALTER TABLE 数据库名.表名 FORCE;

1.4 Instant DDL 不兼容(CHECK TABLE FOR UPGRADE)

错误信息:has done instant ddl, cannot upgrade to 8.0
错误级别:ERROR。

错误原因

这个错误是因为您的 MySQL 5.7数据库中有些表执行过 Instant DDL 操作(主要是 INSTANT ADD COLUMN 秒级加列功能),而这种操作产生的元数据格式与 MySQL 8.0不兼容。

技术背景

问题点
说明
Instant DDL 是什么
一种快速加列功能,只修改表的元数据而不重写表数据,可以秒级完成加列操作
为何不兼容
MySQL 5.7(部分云厂商版本)和 MySQL 8.0的 Instant DDL 实现方式不同,数据字典格式存在差异
MySQL 8.0 的变化
MySQL 8.0重新设计了数据字典结构,引入了 row_version 等新机制,无法正确解析 MySQL 5.7遗留的 Instant DDL 元数据

解决方案

升级前需要重建受影响的表,消除 Instant DDL 的元数据:
-- 1. 检查哪些表执行过 Instant DDL
SELECT b.name from information_schema.INNODB_SYS_INSTANT_COLS a join information_schema.INNODB_SYS_TABLES b on a.table_id=b.table_id;

-- 2. 检查哪些表执行过 modify column
SELECT b.name from information_schema.INNODB_SYS_INSTANT_MODIFIED_COLS a join information_schema.INNODB_SYS_TABLES b on a.table_id=b.table_id;

-- 3. 对这些表执行重建(二选一)
-- 方法一:
OPTIMIZE TABLE 数据库名.表名;

-- 方法二:
ALTER TABLE 数据库名.表名 ENGINE=InnoDB;
重建完成后,表的数据会被重写为标准格式,Instant DDL 的元数据被清除,再次执行升级检查即可通过。

1.5 CHECK TABLE FOR UPGRADE 检查(checkTableOutput)

错误信息:Issues reported by 'check table x for upgrade' command
错误级别:动态(ERROR/WARNING/NOTICE)。

错误原因

MySQL Shell 会对所有非系统表执行 CHECK TABLE ... FOR UPGRADE 命令,该命令会检测表的各种潜在问题。

解决方案

-- 手动执行检查
CHECK TABLE 数据库名.表名 FOR UPGRADE;

-- 根据返回的具体错误信息进行修复
-- 通常的修复方法:
REPAIR TABLE 数据库名.表名;
-- 或
ALTER TABLE 数据库名.表名 FORCE;

二、数据库对象定义检查

2.1 存储过程/函数语法检查(routinesSyntaxCheck)

错误信息:MySQL 8.0 syntax check for routine-like objects
错误级别:ERROR。

错误原因

存储过程、函数、触发器或事件的定义包含 MySQL 8.0 不兼容的语法,最常见的原因是使用了与新保留关键字冲突的标识符。

技术背景

问题点
说明
检查对象
存储过程、函数、触发器、事件
常见原因
使用了新版本的保留关键字作为标识符
检测方式
使用 MySQL 8.0语法解析器验证定义

解决方案

-- 1. 查看存储过程/函数定义
SHOW CREATE PROCEDURE 数据库名.过程名;
SHOW CREATE FUNCTION 数据库名.函数名;

-- 2. 为冲突的标识符添加反引号
-- 修改前
CREATE PROCEDURE test()
BEGIN
SELECT rank FROM users; -- rank 是 MySQL 8.0的保留字
END;

-- 修改后
CREATE PROCEDURE test()
BEGIN
SELECT `rank` FROM users;
END;

-- 3. 重新创建存储过程
DROP PROCEDURE IF EXISTS 数据库名.过程名;
CREATE PROCEDURE 数据库名.过程名 ...

2.2 保留关键字冲突检查(reservedKeywordsCheck)

错误信息:Usage of db objects with names conflicting with new reserved keywords
错误级别:WARNING。

错误原因

数据库对象(Schema、表、列、触发器、视图、存储过程、事件)的名称与 MySQL 8.0新增的保留关键字冲突。

技术背景

MySQL 8.0各版本新增的保留关键字:
版本
新增保留关键字
8.0.11
ADMIN,CUBE,CUME_DIST,DENSE_RANK,EMPTY,EXCEPT,FIRST_VALUE,FUNCTION,GROUPING,GROUPS,JSON_TABLE,LAG,LAST_VALUE,LEAD,NTH_VALUE,NTILE,OF,OVER,PERCENT_RANK,PERSIST,PERSIST_ONLY,RANK,RECURSIVE,ROW,ROWS,ROW_NUMBER,SYSTEM,WINDOW
8.0.14
LATERAL
8.0.17
ARRAY,MEMBER
8.0.31
FULL,INTERSECT

解决方案

-- 1. 查找使用保留关键字的对象
SELECT table_schema, table_name, column_name
FROM information_schema.columns
WHERE column_name IN ('RANK', 'ROWS', 'GROUPS', 'FUNCTION', 'SYSTEM', ...);

-- 2. 修改应用程序 SQL,为这些标识符添加反引号
-- 修改前
SELECT rank, rows FROM my_table;

-- 修改后
SELECT `rank`, `rows` FROM my_table;

-- 3. 或者重命名对象(如果可行)
ALTER TABLE my_table CHANGE rank ranking INT;

2.3 UTF8MB3 字符集检查(utf8mb3Check)

错误信息:Usage of utf8mb3 charset
错误级别:WARNING。

错误原因

数据库或表使用了 utf8(即 utf8mb3)字符集。在 MySQL 8.0中,utf8mb3 已被弃用,建议使用 utf8mb4

技术背景

问题点
说明
utf8mb3 限制
最多只能存储3字节的 UTF-8 字符
utf8mb4 优势
支持完整的 Unicode,包括 emoji 表情符号
MySQL 8.0的变化
utf8 别名将在未来版本指向 utf8mb4

解决方案

-- 1. 查找使用 utf8/utf8mb3 的对象
SELECT table_schema, table_name, column_name, character_set_name
FROM information_schema.columns
WHERE character_set_name IN ('utf8', 'utf8mb3') and table_schema not in ('information_schema','mysql','performance_schema','sys');

-- 2. 转换数据库字符集
ALTER DATABASE 数据库名 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 3. 转换表字符集
ALTER TABLE 数据库名.表名 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 4. 批量转换脚本
SELECT CONCAT('ALTER TABLE `', table_schema, '`.`', table_name,
'` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;')
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
AND table_collation LIKE 'utf8_%';

2.4 MySQL Schema 表名冲突检查(mysqlSchemaCheck)

错误信息:Table names in the mysql schema conflicting with new tables in 8.0
错误级别:ERROR。

错误原因

mysql 系统数据库中存在与 MySQL 8.0新增系统表同名的用户表。

技术背景

MySQL 8.0新增的系统表名:
catalogs, character_sets, collations, column_type_elements, columns,
dd_properties, events, foreign_key_column_usage, foreign_keys,
index_column_usage, index_partitions, index_stats, indexes,
parameter_type_elements, parameters, routines, schemata,
st_spatial_reference_systems, table_partition_values, table_partitions,
table_stats, tables, tablespace_files, tablespaces, triggers,
view_routine_usage, view_table_usage, component, default_roles,
global_grants, innodb_ddl_log, innodb_dynamic_metadata,
password_history, role_edges

解决方案

-- 1. 查找冲突的表
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'mysql'
AND table_name IN ('catalogs', 'character_sets', 'collations', ...);

-- 2. 重命名冲突的表
RENAME TABLE mysql.冲突表名 TO mysql.冲突表名_backup;

-- 或移动到其他数据库
RENAME TABLE mysql.冲突表名 TO other_db.表名;

2.5 外键约束名长度检查(foreignKeyLengthCheck)

错误信息:Foreign key constraint names longer than 64 characters
错误级别:ERROR。

错误原因

外键约束名称超过64个字符。MySQL 8.0严格限制约束名长度不能超过64字符。

解决方案

-- 1. 查找超长约束名
SELECT i.TABLE_SCHEMA, i.TABLE_NAME, i.CONSTRAINT_NAME,
LENGTH(i.CONSTRAINT_NAME) as name_length
FROM information_schema.TABLE_CONSTRAINTS i
WHERE i.CONSTRAINT_TYPE = 'FOREIGN KEY'
AND LENGTH(i.CONSTRAINT_NAME) > 64;

-- 2. 重建外键约束
-- 先删除旧约束
ALTER TABLE 数据库名.表名 DROP FOREIGN KEY 旧约束名;

-- 再创建新约束(使用较短的名称)
ALTER TABLE 数据库名.表名
ADD CONSTRAINT 新约束名 FOREIGN KEY (列名) REFERENCES 引用表(引用列);

2.6 MAXDB SQL 模式检查(maxdbFlagCheck)

错误信息:Usage of obsolete MAXDB sql_mode flag
错误级别:WARNING。

错误原因

存储过程、事件或触发器中持久化了已废弃的 MAXDB sql_mode 选项。

技术背景

问题点
说明
MAXDB 模式作用
使 DATETIME 行为类似 TIMESTAMP
升级影响
MySQL 8.0会自动清除此模式,可能影响1970年前或2037年后的日期处理

解决方案

-- 1. 查找使用 MAXDB 模式的对象
SELECT ROUTINE_SCHEMA, ROUTINE_NAME, SQL_MODE
FROM information_schema.ROUTINES
WHERE SQL_MODE LIKE '%MAXDB%';

-- 2. 重新创建存储过程,移除 MAXDB 模式
-- 导出存储过程定义
SHOW CREATE PROCEDURE 数据库名.过程名;

-- 修改 SQL_MODE,移除 MAXDB
-- 重新创建存储过程

2.7 过时 SQL 模式标志检查(sqlModeFlagCheck)

错误信息:Usage of obsolete sql_mode flags
错误级别:NOTICE。

错误原因

对象中使用了已在 MySQL 8.0中移除的 sql_mode 标志。

技术背景

已移除的 sql_mode 标志:
DB2
MSSQL
MYSQL323
MYSQL40
NO_AUTO_CREATE_USER
NO_FIELD_OPTIONS
NO_KEY_OPTIONS
NO_TABLE_OPTIONS
ORACLE
POSTGRESQL

解决方案

-- 1. 查找使用过时模式的对象
SELECT ROUTINE_SCHEMA, ROUTINE_NAME, SQL_MODE
FROM information_schema.ROUTINES
WHERE SQL_MODE REGEXP 'DB2|MSSQL|MYSQL323|MYSQL40|NO_AUTO_CREATE_USER|ORACLE|POSTGRESQL';

-- 2. 重新创建对象,移除过时的 sql_mode 标志

2.8 ENUM/SET 元素长度检查(enumSetElementLenghtCheck)

错误信息:ENUM/SET column definitions containing elements longer than 255 characters
错误级别:ERROR。

错误原因

ENUM 或 SET 类型的列包含超过255字符的元素值。

解决方案

-- 1. 查找超长元素
SELECT table_schema, table_name, column_name, data_type, character_maximum_length
FROM information_schema.columns
WHERE data_type IN ('enum', 'set')
AND character_maximum_length > 255 and table_schema not in ('information_schema','mysql','performance_schema','sys');

-- 2. 修改列定义,缩短元素值
ALTER TABLE 数据库名.表名
MODIFY COLUMN 列名 ENUM('短值1', '短值2', ...);

2.9 已移除函数检查(removedFunctionsCheck)

错误信息:Usage of removed functions
错误级别:ERROR。

错误原因

视图、存储过程/函数、生成列、触发器或事件中使用了 MySQL 8.0已移除的函数。

技术背景

已移除的函数及替代方案:
已移除函数
替代方案
ENCODE()
AES_ENCRYPT()
DECODE()
AES_DECRYPT()
ENCRYPT()
SHA2()
DES_ENCRYPT()
AES_ENCRYPT()
DES_DECRYPT()
AES_DECRYPT()
PASSWORD()
无直接替代,使用应用层加密
AREA()
ST_AREA()
ASBINARY()
ST_ASBINARY()
ASTEXT()
ST_ASTEXT()
BUFFER()
ST_BUFFER()
CENTROID()
ST_CENTROID()
CONTAINS()
MBRCONTAINS() 或 ST_CONTAINS()
CROSSES()
ST_CROSSES()
DIMENSION()
ST_DIMENSION()
DISJOINT()
MBRDISJOINT() 或 ST_DISJOINT()
DISTANCE()
ST_DISTANCE()
ENDPOINT()
ST_ENDPOINT()
ENVELOPE()
ST_ENVELOPE()
EQUALS()
MBREQUALS() 或 ST_EQUALS()
EXTERIORRING()
ST_EXTERIORRING()
GEOMCOLLFROMTEXT()
ST_GEOMCOLLFROMTEXT()
GEOMCOLLFROMWKB()
ST_GEOMCOLLFROMWKB()
GEOMETRYCOLLECTION()
ST_GEOMETRYCOLLECTION()
GEOMETRYN()
ST_GEOMETRYN()
GEOMETRYTYPE()
ST_GEOMETRYTYPE()
GEOMFROMTEXT()
ST_GEOMFROMTEXT()
GEOMFROMWKB()
ST_GEOMFROMWKB()
GLENGTH()
ST_LENGTH()
INTERIORRINGN()
ST_INTERIORRINGN()
INTERSECTS()
MBRINTERSECTS() 或 ST_INTERSECTS()
ISCLOSED()
ST_ISCLOSED()
ISEMPTY()
ST_ISEMPTY()
ISSIMPLE()
ST_ISSIMPLE()
LINEFROMTEXT()
ST_LINEFROMTEXT()
LINEFROMWKB()
ST_LINEFROMWKB()
LINESTRING()
ST_LINESTRING()
MLINEFROMTEXT()
ST_MLINEFROMTEXT()
MLINEFROMWKB()
ST_MLINEFROMWKB()
MPOINTFROMTEXT()
ST_MPOINTFROMTEXT()
MPOINTFROMWKB()
ST_MPOINTFROMWKB()
MPOLYFROMTEXT()
ST_MPOLYFROMTEXT()
MPOLYFROMWKB()
ST_MPOLYFROMWKB()
MULTILINESTRING()
ST_MULTILINESTRING()
MULTIPOINT()
ST_MULTIPOINT()
MULTIPOLYGON()
ST_MULTIPOLYGON()
NUMGEOMETRIES()
ST_NUMGEOMETRIES()
NUMINTERIORRINGS()
ST_NUMINTERIORRINGS()
NUMPOINTS()
ST_NUMPOINTS()
OVERLAPS()
MBROVERLAPS() 或 ST_OVERLAPS()
POINTFROMTEXT()
ST_POINTFROMTEXT()
POINTFROMWKB()
ST_POINTFROMWKB()
POINTN()
ST_POINTN()
POLYFROMTEXT()
ST_POLYFROMTEXT()
POLYFROMWKB()
ST_POLYFROMWKB()
POLYGON()
ST_POLYGON()
SRID()
ST_SRID()
STARTPOINT()
ST_STARTPOINT()
TOUCHES()
ST_TOUCHES()
WITHIN()
MBRWITHIN() 或 ST_WITHIN()
X()
ST_X()
Y()
ST_Y()

解决方案

-- 1. 查找使用已移除函数的视图
SELECT table_schema, table_name, view_definition
FROM information_schema.views
WHERE view_definition REGEXP 'ENCODE|DECODE|ENCRYPT|PASSWORD|\\\\bAREA\\\\b|\\\\bASBINARY\\\\b'
and table_schema not in ('information_schema','mysql','performance_schema','sys');

-- 2. 修改视图定义,使用替代函数
CREATE OR REPLACE VIEW 视图名 AS
SELECT ST_AREA(geom_column) AS area -- 替换 AREA()
FROM 表名;

-- 3. 类似地修改存储过程、触发器等

2.10 GROUP BY ASC/DESC 语法检查(groupByAscCheck)

错误信息:Usage of removed GROUP BY ASC/DESC syntax
错误级别:ERROR。

错误原因

视图、存储过程/函数、触发器或事件中使用了已移除的 GROUP BY ... ASC/DESC 语法。

技术背景

问题点
说明
旧语法
GROUP BY column ASCGROUP BY column DESC
MySQL 8.0变化
GROUP BY 不再支持 ASC/DESC 修饰符
正确做法
排序应使用 ORDER BY 子句

解决方案

-- 修改前(错误)
SELECT category, COUNT(*)
FROM products
GROUP BY category DESC;

-- 修改后(正确)
SELECT category, COUNT(*)
FROM products
GROUP BY category
ORDER BY category DESC;

2.11 零日期检查(zeroDatesCheck)

错误信息:Zero Date, Datetime, and Timestamp values
错误级别:WARNING。

错误原因

数据库中存在零日期值(如 0000-00-00),或者 sql_mode 未包含 NO_ZERO_DATENO_ZERO_IN_DATE

技术背景

问题点
说明
默认行为变化
MySQL 8.0默认不允许零日期值
影响范围
列默认值、现有数据
sql_mode 变化
NO_ZERO_DATE 和 NO_ZERO_IN_DATE 默认启用

解决方案

-- 1. 查找使用零日期默认值的列
SELECT table_schema, table_name, column_name, column_default
FROM information_schema.columns
WHERE column_default LIKE '0000-00-00%'
and table_schema not in ('information_schema','mysql','performance_schema','sys');

-- 2. 查找包含零日期的数据
SELECT COUNT(*) FROM 表名 WHERE date_column = '0000-00-00';

-- 3. 更新零日期为有效值
UPDATE 表名 SET date_column = '1970-01-01' WHERE date_column = '0000-00-00';

-- 4. 修改列默认值
ALTER TABLE 表名 ALTER COLUMN date_column SET DEFAULT '1970-01-01';
-- 或
ALTER TABLE 表名 ALTER COLUMN date_column SET DEFAULT CURRENT_TIMESTAMP;

2.12 FTS 表名检查(ftsTablenameCheck)

错误信息:Table names containing 'FTS'
错误级别:ERROR(不适用于 8.0.18+ 或 Windows)。

错误原因

表名包含 'FTS' 字符串(区分大小写)。这与 InnoDB 全文索引的内部表命名冲突。

解决方案

-- 1. 查找包含 FTS 的表名
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_name LIKE BINARY '%FTS%';

-- 2. 升级前临时重命名(将任一字母改为小写)
RENAME TABLE myFTStable TO myFtStable;

-- 3. 升级完成后可改回原名
RENAME TABLE myFtStable TO myFTStable;

2.13 生成列函数语义变化检查(changedFunctionsInGeneratedColumnsCheck)

错误信息:Indexes on functions with changed semantics
错误级别:WARNING。

错误原因

生成列上有索引,且这些生成列使用了语义已改变的函数(例如 CAST、CONVERT)。

技术背景

问题点
说明
影响函数
CAST,CONVERT
潜在问题
可能导致复制问题和索引损坏
适用版本
升级到8.0.28+时需注意

解决方案

-- 1. 查找受影响的生成列
SELECT table_schema, table_name, column_name, generation_expression
FROM information_schema.columns
WHERE generation_expression IS NOT NULL
AND generation_expression REGEXP 'CAST|CONVERT' and table_schema not in ('information_schema','mysql','performance_schema','sys');

-- 2. 重建索引
ALTER TABLE 表名 DROP INDEX 索引名;
ALTER TABLE 表名 ADD INDEX 索引名 (生成列名);

2.14 无效 MySQL 5.7名称检查((mysqlInvalid57NamesCheck)

错误信息:Check for invalid table names and schema names used in 5.7
错误级别:ERROR。

错误原因

存在以 #mysql50# 开头的 Schema 或表名,这是 MySQL 5.0 遗留的命名格式。

解决方案

-- 1. 使用 mysqlcheck 工具修复
mysqlcheck --check-upgrade --all-databases
mysqlcheck --fix-db-names --fix-table-names --all-databases

-- 2. 或使用 SQL 命令
ALTER DATABASE `#mysql50#旧名称` UPGRADE DATA DIRECTORY NAME;

2.15 孤立存储过程检查(mysqlOrphanedRoutinesCheck)

错误信息:Check for orphaned routines in 5.7
错误级别:ERROR。

错误原因

存储过程或函数引用的 Schema 已不存在,成为"孤立"状态。

解决方案

-- 1. 查找孤立的存储过程
SELECT ROUTINE_SCHEMA, ROUTINE_NAME, 'is orphaned'
FROM information_schema.routines
WHERE NOT EXISTS (
SELECT SCHEMA_NAME
FROM information_schema.schemata
WHERE ROUTINE_SCHEMA = SCHEMA_NAME
);

-- 2. 删除孤立的存储过程
DROP PROCEDURE IF EXISTS 不存在的 schema.过程名;
DROP FUNCTION IF EXISTS 不存在的 schema.函数名;

2.16 美元符号名称检查(mysqlDollarSignNameCheck)

错误信息:Check for deprecated usage of single dollar signs in object names
错误级别:WARNING。

错误原因

对象名称以美元符号 $ 开头但不以 $ 结尾,这是已弃用的用法。

解决方案

-- 修改对象名称,使其以 $ 结尾
-- 例如:$example 改为 $example$ 或 example
RENAME TABLE `$mytable` TO `$mytable$`;
-- 或
RENAME TABLE `$mytable` TO `mytable`;

2.17 索引过大检查(mysqlIndexTooLargeCheck)

错误信息:Check for indexes that are too large to work on higher versions of MySQL Server than 5.7
错误级别:ERROR。

错误原因

在旧版本 MySQL(5.7.34 之前)中创建的索引过大。对于 compact 或 redundant 行格式的表,索引列不应超过767字节。

解决方案

-- 1. 查找过大的索引
SELECT table_schema, table_name, index_name,
GROUP_CONCAT(column_name) as columns
FROM information_schema.statistics
WHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
GROUP BY table_schema, table_name, index_name
HAVING SUM(sub_part) > 767 OR (SUM(sub_part) IS NULL AND COUNT(*) > 1);

-- 2. 删除过大的索引
ALTER TABLE 表名 DROP INDEX 索引名;

-- 3. 考虑使用前缀索引或更改行格式
ALTER TABLE 表名 ROW_FORMAT=DYNAMIC;
ALTER TABLE 表名 ADD INDEX 索引名 (列名(191));

2.18 空点表语法检查(mysqlEmptyDotTableSyntaxCheck)

错误信息:Check for deprecated '.<table>' syntax used in routines
错误级别:ERROR。

错误原因

存储过程、事件或触发器中使用了已弃用的 .<table> 语法(省略数据库名,只有点和表名)。

解决方案

-- 修改存储过程,使用完整的 database.table 语法
-- 修改前
SELECT * FROM .mytable;

-- 修改后
SELECT * FROM mydb.mytable;

2.19 无效引擎外键检查(mysqlInvalidEngineForeignKeyCheck)

错误信息:Check for columns that have foreign keys pointing to tables from a different database engine
错误级别:ERROR。

错误原因

外键指向使用不同存储引擎的表。这通常是在 FOREIGN_KEY_CHECKS=0 时的错误操作导致的。

解决方案

-- 1. 查找无效的外键
SELECT
fk.TABLE_SCHEMA, fk.TABLE_NAME, fk.CONSTRAINT_NAME,
fk.REFERENCED_TABLE_SCHEMA, fk.REFERENCED_TABLE_NAME,
t1.ENGINE as source_engine, t2.ENGINE as target_engine
FROM information_schema.KEY_COLUMN_USAGE fk
JOIN information_schema.TABLES t1
ON fk.TABLE_SCHEMA = t1.TABLE_SCHEMA AND fk.TABLE_NAME = t1.TABLE_NAME
JOIN information_schema.TABLES t2
ON fk.REFERENCED_TABLE_SCHEMA = t2.TABLE_SCHEMA
AND fk.REFERENCED_TABLE_NAME = t2.TABLE_NAME
WHERE fk.REFERENCED_TABLE_NAME IS NOT NULL
AND t1.ENGINE != t2.ENGINE;

-- 2. 删除无效的外键
ALTER TABLE 表名 DROP FOREIGN KEY 约束名;

-- 3. 或统一存储引擎后重建外键
ALTER TABLE 表名 ENGINE=InnoDB;

三、存储引擎检查

3.1 非原生分区检查(nonNativePartitioningCheck)

错误信息:Partitioned tables using engines with non native partitioning
错误级别:ERROR。

错误原因

分区表使用了不支持原生分区的存储引擎。MySQL 8.0中只有 InnoDB 和 NDB 支持原生分区。

技术背景

问题点
说明
支持原生分区的引擎
InnoDB,NDB/NDBCLUSTER
不支持的引擎
MyISAM,ARCHIVE,CSV 等
MySQL 8.0变化
移除了通用分区处理程序

解决方案

-- 1. 查找使用非原生分区的表
SELECT table_schema, table_name, engine
FROM information_schema.tables
WHERE create_options LIKE '%partitioned%'
AND UPPER(engine) NOT IN ('INNODB', 'NDB', 'NDBCLUSTER');

-- 2. 转换为 InnoDB
ALTER TABLE 数据库名.表名 ENGINE=InnoDB;

-- 3. 或移除分区
ALTER TABLE 数据库名.表名 REMOVE PARTITIONING;

3.2 引擎混淆检查(engineMixupCheck)

错误信息:Tables recognized by InnoDB that belong to a different engine
错误级别:ERROR。

错误原因

表被 InnoDB 引擎识别(存在 .ibd 文件),但 SQL 层认为它属于不同的引擎(如 MyISAM)。这通常是手动删除 InnoDB 表文件后创建同名 MyISAM 表导致的。

解决方案

-- 复杂情况,需要多步骤处理:

-- 1. 重命名当前表
RENAME TABLE 问题表 TO 问题表_temp;

-- 2. 创建虚拟 InnoDB 表(使用相同结构)
CREATE TABLE 问题表 (id INT) ENGINE=InnoDB;

-- 3. 删除虚拟表(清理 InnoDB 数据字典)
DROP TABLE 问题表;

-- 4. 将临时表改回原名
RENAME TABLE 问题表_temp TO 问题表;

四、表空间检查

4.1 循环目录引用检查(circularDirectoryCheck)

错误信息:Circular directory references in tablespace data file paths
错误级别:ERROR。

错误原因

表空间数据文件路径包含循环目录引用(例如 /../)。MySQL 8.0.17 起不再允许这种路径。

解决方案

-- 1. 查找包含循环引用的表空间
SELECT FILE_NAME
FROM INFORMATION_SCHEMA.FILES
WHERE FILE_TYPE = 'TABLESPACE'
AND FILE_NAME LIKE '%/../%'

-- 2. 移动数据文件到正常路径
-- 需要停止 MySQL,手动移动文件,然后更新数据字典
-- 或重建表
ALTER TABLE 表名 ENGINE=InnoDB;

五、系统变量检查

5.1 已移除系统日志变量检查(removedSysLogVars)

错误信息:Removed system variables for error logging to the system log configuration
错误级别:ERROR。

错误原因

配置文件中使用了已移除的系统日志相关变量。

技术背景

已移除变量
替代变量
log_syslog_facility
syseventlog.facility
log_syslog_include_pid
syseventlog.include_pid
log_syslog_tag
syseventlog.tag
log_syslog
无直接替代,使用 log_sink_syseventlog 组件

解决方案

修改 my.cnf 配置文件:
# 修改前
[mysqld]
log_syslog=1
log_syslog_facility=daemon
log_syslog_tag=mysql

# 修改后
[mysqld]
# 加载系统日志组件
log_error_services='log_filter_internal; log_sink_internal; log_sink_syseventlog'

# 使用新变量名
syseventlog.facility=daemon
syseventlog.tag=mysql

5.2 已移除系统变量检查(removedSysVars)

错误信息:Removed system variables
错误级别:ERROR。

错误原因

配置文件中使用了已在 MySQL 8.0中移除的系统变量。

技术背景

已移除变量及替代方案(部分):
已移除变量
替代方案
date_format
datetime_format
have_crypt
ignore_builtin_innodb
ignore_db_dirs
innodb_checksums
innodb_checksum_algorithm
innodb_file_format
无(MySQL 8.0只支持 Barracuda)
innodb_file_format_check
innodb_file_format_max
innodb_large_prefix
无(MySQL 8.0默认启用)
innodb_locks_unsafe_for_binlog
innodb_stats_sample_pages
innodb_stats_transient_sample_pages
innodb_support_xa
无(MySQL 8.0始终启用)
innodb_undo_logs
innodb_rollback_segments
log_warnings
log_error_verbosity
max_tmp_tables
metadata_locks_cache_size
metadata_locks_hash_instances
old_passwords
query_cache_limit
无(查询缓存已移除)
query_cache_min_res_unit
query_cache_size
query_cache_type
query_cache_wlock_invalidate
secure_auth
无(MySQL 8.0始终启用)
sync_frm
tx_isolation
transaction_isolation
tx_read_only
transaction_read_only

解决方案

修改 my.cnf 配置文件,移除或替换已移除的变量:
# 修改前
[mysqld]
query_cache_size=64M
query_cache_type=1
innodb_file_format=Barracuda
tx_isolation=READ-COMMITTED
log_warnings=2

# 修改后
[mysqld]
# 移除 query_cache 相关配置(查询缓存已移除)
# 移除 innodb_file_format(8.0 只支持 Barracuda)
transaction_isolation=READ-COMMITTED
log_error_verbosity=2

5.3 系统变量新默认值检查(sysVarsNewDefaults)

错误信息:System variables with new default values
错误级别:WARNING。

错误原因

某些系统变量在 MySQL 8.0中有了新的默认值,如果应用程序依赖旧的默认值,可能会出现问题。

技术背景

重要的默认值变化:
变量
MySQL 5.7 默认值
MySQL 8.0 默认值
影响
character_set_server
latin1
utf8mb4
新建表的默认字符集
collation_server
latin1_swedish_ci
utf8mb4_0900_ai_ci
新建表的默认排序规则
explicit_defaults_for_timestamp
OFF
ON
TIMESTAMP 列行为
max_allowed_packet
4MB
64MB
单个数据包大小限制
event_scheduler
OFF
ON
事件调度器是否启动
log_bin
OFF
ON
是否启用二进制日志
innodb_autoinc_lock_mode
1
2
自增锁模式
innodb_flush_neighbors
1
0
刷新相邻页
innodb_max_dirty_pages_pct_lwm
0
10
脏页低水位
innodb_undo_tablespaces
0
2
Undo 表空间数量
innodb_undo_log_truncate
OFF
ON
是否截断 Undo 日志
back_log
-1
151
连接队列大小
max_error_count
64
1024
最大错误数
optimizer_trace_max_mem_size
16KB
1MB
优化器跟踪内存

解决方案

如果依赖旧的默认值,在 my.cnf 中显式设置:
[mysqld]
# 保持 MySQL 5.7的字符集行为
character_set_server=latin1
collation_server=latin1_swedish_ci

# 保持 MySQL 5.7的 TIMESTAMP 行为
explicit_defaults_for_timestamp=OFF

# 保持 MySQL 5.7的自增锁模式(如果有基于语句的复制)
innodb_autoinc_lock_mode=1

# 如果不需要二进制日志
skip-log-bin

六、认证插件检查

6.1 默认认证插件检查(defaultAuthenticationPlugin)

错误信息:New default authentication plugin considerations
错误级别:WARNING(手动检查)。

错误原因

MySQL 8.0的默认认证插件从 mysql_native_password 改为 caching_sha2_password,可能导致旧客户端连接问题。

技术背景

问题点
说明
新默认插件
caching_sha2_password
旧默认插件
mysql_native_password
安全性
caching_sha2_password 提供更强的密码哈希
兼容性
旧客户端/驱动可能不支持新插件

解决方案

方案一:升级客户端驱动到支持 caching_sha2_password 的版本。
方案二:临时使用旧认证插件。
# my.cnf
[mysqld]
default_authentication_plugin=mysql_native_password
方案三:为特定用户使用旧插件。
-- 创建使用旧插件的用户
CREATE USER 'user'@'host' IDENTIFIED WITH mysql_native_password BY 'password';

-- 或修改现有用户
ALTER USER 'user'@'host' IDENTIFIED WITH mysql_native_password BY 'password';

七、问题级别说明

级别
说明
处理要求
ERROR
严重问题,必须在升级前解决
升级会失败或导致数据不可用
WARNING
潜在问题,建议解决
可能影响升级后的功能或性能
NOTICE
提示信息
不影响升级,但值得关注

附录:快速检查脚本

-- 综合预检查脚本
-- 运行此脚本可快速发现大部分升级问题

-- 1. 检查旧时间格式
SELECT '旧时间格式' as check_type, table_schema, table_name, column_name
FROM information_schema.columns
WHERE column_type LIKE '%5.5 binary format%'
and table_schema not in ('information_schema','mysql','performance_schema','sys');

-- 2. 检查 utf8mb3 字符集
SELECT 'UTF8MB3字符集' as check_type, table_schema, table_name, column_name
FROM information_schema.columns
WHERE character_set_name IN ('utf8', 'utf8mb3') and table_schema not in ('information_schema','mysql','performance_schema','sys')
LIMIT 20;

-- 3. 检查零日期默认值
SELECT '零日期默认值' as check_type, table_schema, table_name, column_name
FROM information_schema.columns
WHERE column_default LIKE '0000-00-00%' and table_schema not in ('information_schema','mysql','performance_schema','sys')
LIMIT 20;

-- 4. 检查非 InnoDB 分区表
SELECT '非原生分区' as check_type, table_schema, table_name, engine
FROM information_schema.tables
WHERE create_options LIKE '%partitioned%'
AND UPPER(engine) NOT IN ('INNODB', 'NDB', 'NDBCLUSTER') and table_schema not in ('information_schema','mysql','performance_schema','sys');

-- 5. 检查外键约束名长度
SELECT '外键名过长' as check_type,
SUBSTRING_INDEX(id, '/', 1) as db_name,
SUBSTRING_INDEX(id, '/', -1) as table_name,
LENGTH(SUBSTRING_INDEX(id, '/', -1)) as name_length
FROM information_schema.innodb_sys_foreign
WHERE LENGTH(SUBSTRING_INDEX(id, '/', -1)) > 64;

-- 6. 检查哪些表执行过 Instant DDL
SELECT b.name from information_schema.INNODB_SYS_INSTANT_COLS a join information_schema.INNODB_SYS_TABLES b on a.table_id=b.table_id;

-- 7. 检查哪些表执行过 modify column
SELECT b.name from information_schema.INNODB_SYS_INSTANT_MODIFIED_COLS a join information_schema.INNODB_SYS_TABLES b on a.table_id=b.table_id;

-- 8. 检查孤立存储过程
SELECT '孤立存储过程' as check_type, ROUTINE_SCHEMA, ROUTINE_NAME
FROM information_schema.routines
WHERE NOT EXISTS (
SELECT SCHEMA_NAME
FROM information_schema.schemata
WHERE ROUTINE_SCHEMA = SCHEMA_NAME
);

参考资料