跨大版本MySQL迁移(如5.7→8.0)需重点验证sql_mode、JSON解析、GROUP BY严格性、保留字(如rank)、字符集、GTID、锁行为及执行计划变化,否则易引发隐性故障。

确认 MySQL 版本兼容性差异
跨大版本迁移(如 5.7 → 8.0)最常触发隐式行为变更,不是所有 SQL 都能“无缝运行”。关键要看 sql_mode 默认值、JSON 字段解析逻辑、GROUP BY 严格性、关键字保留情况(比如 rank 在 8.0 成为保留字)。
实操建议:
- 在目标版本上执行
SELECT VERSION(), @@sql_mode;,比对源库输出 - 用
mysqldump --no-data --skip-triggers --skip-routines导出 DDL,人工检查CREATE TABLE中的字段类型是否被自动改写(如TEXT变TINYTEXT) - 重点查
information_schema.INNODB_TRX和慢查询日志中高频使用的函数,比如UNIX_TIMESTAMP()在 8.0.28+ 对DATETIME参数支持更严格
识别应用层直连 SQL 的隐性依赖
ORM 或胶水脚本里常有绕过标准语法的写法,比如手动拼接 ORDER BY ? 后跟字段名而非参数占位符,或依赖 MySQL 5.7 的非标准 GROUP_CONCAT 截断行为(8.0 默认长度是 1024,5.7 是 1024 但部分旧客户端会误读为无限)。
实操建议:
- 抓取线上全量 SQL(用
pt-query-digest+ slow log 或performance_schema.events_statements_summary_by_digest),过滤出含SELECT ... GROUP BY、INSERT IGNORE、REPLACE INTO的语句,逐条验证目标版本返回结果是否一致 - 检查应用配置里是否硬编码了
max_allowed_packet、wait_timeout等参数,8.0 默认值可能更激进(如wait_timeout=28800vs 5.7 的28800表面相同,但连接空闲检测逻辑有调整)
验证备份与恢复链路的完整性
迁移不是只跑一次 mysqldump | mysql 就完事。真实风险藏在字符集转换、GTID 开关状态、主从复制过滤规则等细节里。
实操建议:
- 导出时显式指定
--default-character-set=utf8mb4,并确认源库character_set_server和各表COLLATION实际值(SHOW CREATE TABLE查),避免 utf8mb3 被静默转成 utf8mb4 后索引长度超限 - 若启用 GTID,必须保证
gtid_mode=ON且enforce_gtid_consistency=ON在源库已稳定运行至少一个完整 binlog 周期,否则mysqldump --set-gtid-purged=ON会失败 - 用
mysqlcheck --check-upgrade扫描迁移后的库,它会报出诸如 “Column 'xxx' is of type JSON but has no default value” 这类 8.0 强制校验项
压测时重点观察锁行为与执行计划漂移
同样的 SQL,在 8.0 的优化器下可能走错索引,或因 cost_model 参数变化导致并发更新锁等待时间翻倍。这不是语法错误,但会让服务在高峰直接雪崩。
实操建议:
- 用
EXPLAIN FORMAT=TRADITIONAL对比迁移前后同一条 SQL 的key、rows、Extra字段,特别注意是否出现Using filesort或Using temporary新增 - 在目标环境用
sys.schema_table_statistics_with_buffer查看表级锁等待次数,对比迁移前后同一批事务的io_read_requests和io_write_requests是否异常升高 - 不要只压单条 SQL,要模拟真实业务事务组合(比如先
UPDATE再SELECT FOR UPDATE),MySQL 8.0 的行锁实现细节和死锁检测阈值有调整
真正卡住迁移的往往不是报错,而是某条每天只跑一次的报表 SQL,在 8.0 下执行时间从 2 秒变成 2 分钟,且没有任何 warning 提示——得靠压测时主动捞 performance_schema.events_statements_history_long 才能发现。


















