导出时未加--compatible导致5.7+导入报错,因5.7默认启用strict_trans_tables而允许非法日期;应使用--compatible=mysql40导出,并统一字符集为utf8mb4,导入后执行analyze table更新统计信息。

mysqldump导出时没加--compatible,导入5.7+报错Invalid default value for 'xxx'
MySQL 5.7 默认开启 STRICT_TRANS_TABLES,而老版本(如5.6)允许0000-00-00这类非法日期作为默认值。直接导出再导入会触发严格模式校验失败。
实操建议:
- 导出时显式指定兼容模式:
mysqldump --compatible=mysql40 --skip-extended-insert -u root -p db_name > dump.sql(mysql40能绕过大部分默认值校验) - 避免用
--compatible=ansi或postgresql——它们会改写语法,反而增加解析负担 - 如果目标库是8.0,还需注意
sql_mode中是否含NO_ZERO_DATE,临时关闭它比改dump更稳妥:SET sql_mode = 'STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION';
导入时卡在Creating table xxx,实际是字符集不匹配
常见于从 Latin1 编码的旧库导出、导入到默认utf8mb4的新库:表结构里CHARSET=latin1被保留,但字段定义没同步更新,导致后续插入时报Incorrect string value。
实操建议:
- 导出时强制统一字符集:
mysqldump --default-character-set=utf8mb4 -u root -p db_name > dump.sql - 导入前检查 dump 文件头是否有
SET NAMES latin1,手动替换成SET NAMES utf8mb4 - 若已导入部分表,别急着删库重来——用
ALTER TABLE tbl CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;逐表修复
mysqldump --single-transaction在5.6以下主从环境中可能丢数据
--single-transaction依赖一致性快照,但 MySQL 5.5 及更早版本在启用binlog_format=STATEMENT时,某些DDL(如ALTER TABLE)会隐式提交事务,导致快照失效。结果是 dump 中混入了中间态数据。
实操建议:
- 确认源库版本和 binlog 格式:
SELECT @@version, @@binlog_format; - 5.6以下必须改用
--lock-all-tables(虽慢但安全),或先停写再 dump - 不要迷信
--single-transaction能“完全无锁”——它只对 InnoDB 有效,MyISAM 表仍会被锁
大表导入后SHOW TABLE STATUS显示行数为0,但SELECT COUNT(*)有数据
这是 MySQL 统计信息未刷新的典型表现,尤其发生在跳过CREATE TABLE语句、直接INSERT大量数据的 dump 场景(比如用了--skip-create-options或手工删了建表语句)。
实操建议:
- 导入完成后立刻执行:
ANALYZE TABLE table_name;(不是OPTIMIZE,后者会锁表且不更新统计) - 若批量操作,可脚本化:
mysql -u root -p -e "SELECT CONCAT('ANALYZE TABLE ', table_name, ';') FROM information_schema.tables WHERE table_schema='db_name';" | mysql -u root -p db_name - 别依赖
Rows字段做业务判断——它只是估算值,SELECT COUNT(*)才是真实结果
跨版本迁移最麻烦的从来不是命令怎么敲,而是两边默认行为的差异藏在配置深处,比如sql_mode、explicit_defaults_for_timestamp、甚至lower_case_table_names。导之前先SELECT @@sql_mode, @@explicit_defaults_for_timestamp, @@lower_case_table_names;对比清楚,比事后修 dump 省三倍时间。











