上周帮一个做电商的朋友处理数据库迁移,他之前用mysqldump导数据,搞了整整一个通宵,结果第二天发现订单表少了三百多条记录。他急得直跺脚,说这要是丢单了,老板能把他生吞了。

这事让我想起很多人的误区——总觉得数据库迁移就是把数据拷过去这么简单。实际上,MySQL表迁移最怕的不是慢,而是丢。你辛辛苦苦跑了一晚上脚本,对账发现数据对不上,那种崩溃感比加班还难受。
今天我就把压箱底的方法拿出来,三步走,保证你迁移完数据一条不丢。这套方法我在生产环境用了五年,迁移过上百个库,最大的一个表有八千万条记录,从来没出过岔子。
第一步,先搞清楚你要迁移什么。很多人上来就mysqldump一把梭,这是大忌。你得先分析表结构,看哪些是InnoDB,哪些是MyISAM,哪些表有外键约束,哪些表有自增主键。特别是自增主键,迁移完如果主键冲突,那才是真灾难。
我一般会先跑一条SQL看表的总行数,然后记录下最大自增值。比如你有个订单表,最大订单号是102345,那迁移后新库里的自增值必须大于这个数。MySQL 5.7以后有个参数叫AUTO_INCREMENT,迁移前在目标库里先把这个值设好,比如设成102400,留点余量,这样就算迁移过程中有并发写入,也不会撞车。
第二步,选择正确的迁移工具。这里我强烈推荐用mysqldump加--single-transaction参数,这个参数特别关键,它能在不锁表的情况下做一致性快照。什么意思呢?就是你导出的时候,别的程序还在往表里写数据,但导出来的快照是一致的,不会出现前后矛盾的情况。
如果你用的是Percona的XtraBackup,那就更稳了。它能做物理备份,直接复制数据文件,速度比逻辑备份快十倍不止。特别是表特别大的时候,用XtraBackup能省一半时间。我那个八千万条记录的表,用mysqldump导要四十分钟,换XtraBackup只要六分钟。
还有个细节,导出前一定要把binlog开着。binlog是MySQL的二进制日志,记录所有数据变更。万一迁移过程中出问题,你还能靠binlog做增量恢复,把丢失的数据找回来。这就像开车系安全带,平时觉得碍事,真出事能救命。
第三步,导入后必须做校验。这一步最容易被忽略,但恰恰是最重要的。很多人导入完就算完事了,结果过了一个月才发现数据对不上,那时候想追责都找不着源头。
我的做法是,导入完成后立刻跑三条SQL。第一条,查总行数,和源库比对。第二条,查最大ID和最小ID,确保没有空洞。第三条,随机抽几条记录,比对关键字段的值。
拿订单表举例,源库有152347行,新库必须也是152347行。最大订单号源库是102345,新库也得是这个数。然后随机抽三个订单,看看金额、用户ID、下单时间是不是和源库一致。如果这三条都过了,基本可以放心。
还有一个进阶玩法,用CHECKSUM TABLE命令。这个命令会计算整张表的校验和,如果源库和新库的校验和一致,说明数据完全一样,一个字节都不差。不过这个命令在大表上跑起来比较慢,我一般只在关键表上用。
前两个月有个做金融系统的客户,他们迁移用户资产表,就是用我这套方法。那个表一个亿的数据,跑完校验发现行数对上了,但checksum对不上。一查,原来是某个用户的余额字段精度丢了,差了0.01元。你说这种问题,光看行数根本发现不了,必须靠checksum这种硬核校验。
说个很多人不知道的小技巧。迁移完成后,别急着切流量。我习惯在新库上开一个只读账号,让开发同事用测试数据跑一遍核心业务流程。比如商城系统,就模拟用户下单、支付、退款,看看新库能不能正常处理。确认没问题了,再切正式流量。
用这套方法,我上个月帮一个在线教育平台迁移课程表,他们二百万条记录,前后花了不到半小时,校验全过,零丢失。老板还专门发了封表扬邮件,说这次迁移是他们公司历史上最顺利的一次。
其实数据库迁移这事,说难也难,说简单也简单。难的是你考虑不周全,简单的是只要你按流程走,把每一步都做到位,数据就不会丢。三步走,每一步都踩实了,零丢失就是顺理成章的事。
下次你要是再遇到MySQL表迁移,别慌,先分析表结构,选对工具,导完做校验。这三步走完,你也能拍着胸脯跟领导说:数据一条不少。


