物理拷贝快但须同版本同架构,逻辑导入兼容性好但锁表时间长,生产环境推荐物理基础+逻辑增量的混合方案,并需同步权限、时区和字符集。

物理拷贝快但必须同版本同架构
物理拷贝本质是直接复制数据文件(如 ibdata1、ib_logfile0、表空间文件),跳过SQL解析和引擎层写入,所以速度极快。但它要求源库和目标库的 MySQL 版本、字符集、页大小(innodb_page_size)、行格式(ROW_FORMAT)完全一致,且操作系统架构不能跨大端/小端(比如 x86_64 → ARM64 通常不行)。
常见错误现象:Table 'xxx' doesn't exist 或启动失败报 InnoDB: Database page corruption,基本就是页结构或校验不匹配。
- 只适用于同版本 MySQL(如 8.0.33 → 8.0.33),跨小版本(8.0.33 → 8.0.34)也可能因内部字典变更失败
- 必须停机:源库需
FLUSH TABLES WITH READ LOCK+mysqldump --single-transaction不够用,物理拷贝前得彻底停写 - 目标实例的
datadir必须为空,且innodb_force_recovery等参数不能残留干扰启动 - 系统表空间(
ibdata1)和 redo log(ib_logfile*)必须一并拷贝,漏一个就起不来
逻辑导入兼容性好但锁表时间长
用 mysqldump 或 mysqlpump 导出 SQL,再用 mysql 客户端执行导入,本质是重放 DDL + DML。它不依赖底层文件格式,所以能跨版本(5.7 → 8.0)、跨平台、甚至跨存储引擎(MyISAM → InnoDB)。
但问题出在“重放”本身:大表导入时,单线程执行 INSERT 可能卡住几小时,期间目标库无法提供服务;如果没关 autocommit,事务日志暴涨还可能填满磁盘。
- 导出时加
--skip-triggers --skip-routines --skip-events避免权限或定义冲突,后续单独处理 - 导入前务必确认目标库
sql_mode与源库一致,否则STRICT_TRANS_TABLES缺失会导致隐式截断不报错 - 大表建议用
--tab模式生成 CSV,配合LOAD DATA INFILE,比纯 SQL 快 3–5 倍 -
mysqldump --single-transaction在源库高并发更新下仍可能因 MVCC 快照滞后导致部分数据不一致
混合方案:物理基础 + 逻辑增量
生产环境真正可行的迁移,往往是物理拷贝打底、逻辑补差。先停写一小段时间做物理快照,恢复到目标实例后,再用 mysqlbinlog 解析源库最后的 binlog,把停机窗口内的变更追上去。
这个方案难点不在工具链,而在时间点对齐:物理拷贝完成时刻的 binlog 位置(SHOW MASTER STATUS)必须精确记录,否则增量会丢或重放。
- 物理拷贝完成后,立刻在源库执行
FLUSH BINARY LOGS,确保后续 binlog 干净可截取 - 用
mysqlbinlog --start-position=XXX从记录位置开始读,避免从头解析几GB日志 - 目标库导入前设
SET SESSION FOREIGN_KEY_CHECKS=0,否则外键约束会让INSERT失败 - 如果源库开启了 GTID,必须用
--include-gtids和--skip-gtids配合,否则目标库会拒绝重复 GTID
别忽略权限、时区和字符集这三个隐形坑
物理拷贝不会带用户权限,逻辑导入默认也不导出 mysql.user 表(除非显式加 --all-databases)。更麻烦的是时区和字符集——它们不存于数据文件,却直接影响查询结果。
比如源库 character_set_server=utf8mb4,目标库是 utf8,哪怕数据文件一样,中文插入也会变成问号;又比如源库 time_zone='+00:00',目标库是 'SYSTEM',DATETIME 字段看起来一样,但 TIMESTAMP 会自动转换出错。
- 权限同步用
SELECT CONCAT('CREATE USER ', QUOTE(user), '@', QUOTE(host), ';') FROM mysql.user;手动生成建用户语句,再导出授权 - 检查双方
SHOW VARIABLES LIKE '%time_zone%';和%character_set%,不一致必须提前改配置并重启 - 目标库初始化时用
--defaults-file指定含default-time-zone和collation-server的配置,别依赖 my.cnf 默认值











