mysql 5.7升级8.0需重点检查sql_mode严格模式、显式定义主键与降序索引、统一utf8mb4字符集、适配系统表结构变更,并通过测试环境验证隐式类型转换风险。

升级前必须检查 SQL_MODE 和严格模式
MySQL 5.7 升级到 8.0 时,STRICT_TRANS_TABLES 默认启用,而旧版本可能长期运行在宽松模式下。一旦开启,INSERT INTO t VALUES ('') 这类插入空字符串到 NOT NULL 字段的操作会直接报错 ERROR 1364 (HY000): Field doesn't have a default value。
实操建议:
- 升级前用
SELECT @@sql_mode;记录当前值,并在测试环境模拟开启STRICT_TRANS_TABLES和ONLY_FULL_GROUP_BY - 检查应用日志中是否已有
Truncated incorrect DOUBLE value或Incorrect datetime value类警告——这些在 8.0 中会变成错误 - 若需临时兼容,可在配置中显式设为
sql_mode = 'NO_ENGINE_SUBSTITUTION',但不推荐长期使用
慎用 MySQL 8.0 新默认行为:隐藏主键与降序索引
MySQL 8.0.12+ 对 CREATE TABLE 隐式添加 PRIMARY KEY 的行为已移除,且 ORDER BY 使用降序索引时优化器策略变化明显。老代码里写 ORDER BY id DESC LIMIT 10 在 5.7 可能走索引,但在 8.0 若未显式建 INDEX (id DESC),可能退化为文件排序。
实操建议:
- 升级前用
mysqldump --no-create-info导出数据,再用mysqlcheck --check-upgrade扫描表结构风险 - 对所有含
ORDER BY ... DESC的慢查询,执行EXPLAIN FORMAT=TREE确认是否仍走索引 - 避免依赖隐式主键逻辑,所有表显式定义
PRIMARY KEY,哪怕只是id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
字符集与排序规则变更直接影响连接和比较
MySQL 8.0 默认字符集从 latin1 改为 utf8mb4,默认排序规则从 latin1_swedish_ci 变为 utf8mb4_0900_ai_ci。这意味着:客户端未声明 charset=utf8mb4 时,连接层可能触发隐式转换;WHERE name = 'abc' 在不同排序规则下可能命中不同索引,甚至改变结果顺序。
实操建议:
- 在
my.cnf中统一设置:collation-server = utf8mb4_0900_ai_ci、character-set-server = utf8mb4,并重启后验证SHOW VARIABLES LIKE 'collation%'; - 检查所有连接字符串(如 JDBC 的
useUnicode=true&characterEncoding=utf8mb4),缺失会导致乱码或Incorrect string value错误 - 对已存在的
utf8字段(实际是utf8mb3),用ALTER TABLE t MODIFY c VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;显式升级,别依赖自动转换
系统表结构变更让权限与元数据查询失效
MySQL 8.0 彻底移除了 mysql.user 表的密码字段,改用 authentication_string;同时 INFORMATION_SCHEMA 中部分视图字段名调整(如 TABLES.CREATE_TIME 类型从 DATETIME 变为 TIMESTAMP)。依赖 SELECT password FROM mysql.user 或硬编码字段顺序的运维脚本会直接报错。
实操建议:
- 禁用所有直接查
mysql系统库的业务逻辑,改用SHOW GRANTS FOR 'u'@'h';或官方提供的performance_schema视图 - 将
INFORMATION_SCHEMA查询改为显式指定字段名,例如不用SELECT * FROM TABLES,而用SELECT TABLE_SCHEMA, TABLE_NAME, CREATE_TIME FROM TABLES - 升级后立即运行
mysql_upgrade(8.0.16+ 已弃用,但升级脚本仍需调用它触发内部元数据校验)
真正麻烦的不是大版本号跳变,而是那些没被日志标记、却在某个凌晨批量 INSERT 时突然卡住的隐式类型转换——它们往往藏在 ORM 自动生成的 SQL 里,得靠 slow_query_log + log_queries_not_using_indexes 组合才能揪出来。










