目录
存储引擎检查
表空间检查
系统变量检查
认证插件检查
问题级别说明
附录
参考资料
一、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_typeFROM information_schema.columnsWHERE 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_nameFROM information_schema.innodb_sys_tables tLEFT JOIN information_schema.tables itON CONCAT(it.TABLE_SCHEMA, '/', it.TABLE_NAME) = t.NAMEWHERE it.TABLE_NAME IS NULLAND 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+(推荐)
方案二:升级前重建受影响的表
-- 查找受影响的表SELECT table_schema, table_name, column_name, data_typeFROM information_schema.columnsWHERE 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 DDLSELECT 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 columnSELECT 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()BEGINSELECT rank FROM users; -- rank 是 MySQL 8.0的保留字END;-- 修改后CREATE PROCEDURE test()BEGINSELECT `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_nameFROM information_schema.columnsWHERE 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_nameFROM information_schema.columnsWHERE 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.tablesWHERE 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_nameFROM information_schema.tablesWHERE 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_lengthFROM information_schema.TABLE_CONSTRAINTS iWHERE 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_MODEFROM information_schema.ROUTINESWHERE 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_MODEFROM information_schema.ROUTINESWHERE 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_lengthFROM information_schema.columnsWHERE 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_definitionFROM information_schema.viewsWHERE 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 视图名 ASSELECT 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 ASC 或 GROUP BY column DESC |
MySQL 8.0变化 | GROUP BY 不再支持 ASC/DESC 修饰符 |
正确做法 | 排序应使用 ORDER BY 子句 |
解决方案
-- 修改前(错误)SELECT category, COUNT(*)FROM productsGROUP BY category DESC;-- 修改后(正确)SELECT category, COUNT(*)FROM productsGROUP BY categoryORDER BY category DESC;
2.11 零日期检查(zeroDatesCheck)
错误信息:
Zero Date, Datetime, and Timestamp values。错误级别:WARNING。
错误原因
数据库中存在零日期值(如
0000-00-00),或者 sql_mode 未包含 NO_ZERO_DATE 和 NO_ZERO_IN_DATE。技术背景
问题点 | 说明 |
默认行为变化 | MySQL 8.0默认不允许零日期值 |
影响范围 | 列默认值、现有数据 |
sql_mode 变化 | NO_ZERO_DATE 和 NO_ZERO_IN_DATE 默认启用 |
解决方案
-- 1. 查找使用零日期默认值的列SELECT table_schema, table_name, column_name, column_defaultFROM information_schema.columnsWHERE 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_nameFROM information_schema.tablesWHERE 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_expressionFROM information_schema.columnsWHERE generation_expression IS NOT NULLAND 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-databasesmysqlcheck --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.routinesWHERE NOT EXISTS (SELECT SCHEMA_NAMEFROM information_schema.schemataWHERE 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$ 或 exampleRENAME 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 columnsFROM information_schema.statisticsWHERE table_schema NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')GROUP BY table_schema, table_name, index_nameHAVING 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. 查找无效的外键SELECTfk.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_engineFROM information_schema.KEY_COLUMN_USAGE fkJOIN information_schema.TABLES t1ON fk.TABLE_SCHEMA = t1.TABLE_SCHEMA AND fk.TABLE_NAME = t1.TABLE_NAMEJOIN information_schema.TABLES t2ON fk.REFERENCED_TABLE_SCHEMA = t2.TABLE_SCHEMAAND fk.REFERENCED_TABLE_NAME = t2.TABLE_NAMEWHERE fk.REFERENCED_TABLE_NAME IS NOT NULLAND 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, engineFROM information_schema.tablesWHERE create_options LIKE '%partitioned%'AND UPPER(engine) NOT IN ('INNODB', 'NDB', 'NDBCLUSTER');-- 2. 转换为 InnoDBALTER 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_NAMEFROM INFORMATION_SCHEMA.FILESWHERE 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=1log_syslog_facility=daemonlog_syslog_tag=mysql# 修改后[mysqld]# 加载系统日志组件log_error_services='log_filter_internal; log_sink_internal; log_sink_syseventlog'# 使用新变量名syseventlog.facility=daemonsyseventlog.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=64Mquery_cache_type=1innodb_file_format=Barracudatx_isolation=READ-COMMITTEDlog_warnings=2# 修改后[mysqld]# 移除 query_cache 相关配置(查询缓存已移除)# 移除 innodb_file_format(8.0 只支持 Barracuda)transaction_isolation=READ-COMMITTEDlog_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=latin1collation_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_nameFROM information_schema.columnsWHERE 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_nameFROM information_schema.columnsWHERE 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_nameFROM information_schema.columnsWHERE 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, engineFROM information_schema.tablesWHERE 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_lengthFROM information_schema.innodb_sys_foreignWHERE LENGTH(SUBSTRING_INDEX(id, '/', -1)) > 64;-- 6. 检查哪些表执行过 Instant DDLSELECT 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 columnSELECT 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_NAMEFROM information_schema.routinesWHERE NOT EXISTS (SELECT SCHEMA_NAMEFROM information_schema.schemataWHERE ROUTINE_SCHEMA = SCHEMA_NAME);