数据库迁移这事儿,说大不大,说小不小。往小了说,就是数据从A库搬到B库;往大了说,一个亿级记录的表,搬完之后差一条,业务方就能找你拼命。我见过太多团队,迁移前信心满满,迁移后哭爹喊娘,查来查去,问题全出在数据校验这步没做好。今天咱们就掰开揉碎,聊聊怎么把数据校验做到位,让迁移这事儿真正零失误。

先说个真事儿。去年有个朋友的公司做核心库迁移,从Oracle迁到PostgreSQL,技术方案写了三十多页,评审过了三轮,结果上线当晚就炸了——订单表少了两万条记录。后来排查发现,不是迁移工具丢数据,而是源库在迁移过程中有一张分区表的数据还在持续写入,迁移脚本没做增量捕获,直接漏掉了。这事儿最讽刺的是,他们其实做了校验,但只校验了表行数,两张表行数一对比,数字一样就放行了。可他们用的是SELECT COUNT(*),这玩意儿在大表上本来就有误差,加上分区表的数据变动,数字对上了纯属巧合。
所以第一课,千万别迷信行数校验。行数一致不代表数据一致,行数不一致也不代表数据一定有问题——比如源库有脏数据,目标库做了清洗,行数自然不一样。更靠谱的做法是校验哈希值。把整张表的所有列拼成一个字符串,算个MD5或CRC32,源库算一遍,目标库算一遍,对上了才敢说基本一致。但这里有个坑,不同数据库的排序规则、字段默认值、甚至浮点数的精度都可能影响拼接结果。比如Oracle的VARCHAR2和PostgreSQL的TEXT,存储方式不同,拼出来的字符串可能就差一个空格。所以做哈希校验前,得先统一字段格式,或者用数据库自带的校验工具,像MySQL的pt-table-checksum,它专门处理这种跨库差异。
说完哈希,再说说抽样校验。有团队觉得全量哈希太慢,就搞抽样,随机抽个5%或者10%的数据比对。这思路没错,但抽样的方式得讲究。你要是按行号随机抽,大概率抽到的都是普通数据,那些特殊值——比如NULL、空字符串、超长文本、特殊字符——全漏过去了。我建议分层抽样,先按表的业务特征分层,比如按时间字段分成近一个月、近一年、历史数据,每层再随机抽。另外,抽样校验只能作为辅助手段,不能替代全量校验。真有团队图省事,只做抽样,结果漏掉的那5%恰好是问题数据,还是得回滚。
接下来聊聊增量校验。很多迁移不是一锤子买卖,源库还在跑业务,数据不停在变。这时候你得先做全量迁移,再做增量同步,在业务切换的瞬间做最终校验。但增量同步有个麻烦,数据在同步过程中可能产生中间状态,比如一条记录在源库更新了三次,同步到目标库时可能只同步了最终版本,中间版本丢了,但业务其实不关心中间版本。可校验工具如果按每条记录比对,就会报出大量的“不一致”,其实这些是预期内的。所以在增量校验时,得先明确规则:哪些字段允许差异,哪些字段必须一致。比如订单状态字段必须一致,但更新时间字段允许有延迟。这个规则要在迁移前就定好,写进校验脚本里,别等校验报告出来了一堆红叉,才临时开会讨论哪些算合理差异。
再有个容易踩的坑,就是大字段和特殊数据类型的校验。像TEXT、BLOB、JSONB这种类型,直接比对字符串或者二进制内容,效率很低,而且容易因为字符集转换出问题。比如源库是UTF-8,目标库是GBK,文本里的中文字符可能就变了。这时候得先做字符集验证,确认转换规则没问题,再用专门的校验函数。对于JSON类型的字段,不能直接比对整个字符串,得解析成结构化数据再比对,因为JSON里的键值顺序可能不同,但实际数据是一样的。我见过一个团队,就是因为JSON字段里多了一个空格,校验报告报了几千条差异,发现全是误报。
校验的时机也有讲究。别等所有数据迁移完了才启动校验,那样发现问题太晚,回滚成本高。正确做法是分阶段校验:迁移完一张表,立刻校验一张表;全量迁移完成后,做一次全量校验;增量同步过程中,定期做增量校验;业务切换前,再做一次最终校验。这四次校验各有侧重,第一轮抓大问题,第二轮抓遗漏,第三轮抓同步延迟,第四轮抓最终一致性。每次校验的结果都要留档,方便后面对比。而且校验脚本要幂等,能重复执行,别跑一遍就没了。
说说校验报告和问题处理。校验不是跑完就完事,得生成一份可读的报告,列出差异数量、差异类型、影响范围。报告里不能只写“有差异”,得具体到哪张表、哪个字段、源库值是什么、目标库值是什么。这样业务方才能判断差异是否影响业务。处理差异时,别急着改数据,先分类:有的是迁移工具的bug,有的是源库的脏数据,有的是业务允许的合理差异。分类之后,再决定是修目标库、修源库,还是直接忽略。这个过程最好有业务方参与,别让技术人员自己拍板。
数据库迁移零失误,听起来像口号,但做起来全靠细节。校验这事儿,没有捷径,也没有银弹。你投入多少心思,数据就给你多少回报。别嫌校验麻烦,也别想着上线后再说,真出了事,背锅的是你,熬夜查数据的也是你。把这套攻略吃透,把校验做扎实,迁移这事儿,其实也没那么可怕。


