跨云迁移数据一致性校验需分阶段、带上下文执行,不能仅依赖COUNT(*)或DTS内置校验;pt-table-checksum要求目标库为从库、关闭GTID跳过、对无主键表指定chunk-index;MD5比对须显式处理NULL、时区、JSON等细节;静态校验需停写,DTS内置校验禁DDL,准实时校验靠binlog位点+关键单据验证;静默截断等问题需上线后监控暴露。

跨云迁移中数据一致性校验不是“跑个工具就完事”,而是必须分阶段、分对象、带上下文地执行。只比 COUNT(*) 或只依赖 DTS 内置校验,大概率漏掉字段值错位、JSON 空格差异、时区隐式转换、外键孤儿记录等真实不一致。
用 pt-table-checksum 做行级校验前必须确认三件事
这个工具是目前最可靠的跨实例行级比对方案,但它不是开箱即用的“黑盒”:
- 目标库必须配置为源库的从库(或至少能模拟复制关系),
pt-table-checksum依赖replicate表写入校验结果,并通过从库回放来触发比对逻辑;纯双写或直连导入场景下它无法工作 - 必须关闭 GTID 自动跳过机制:
SET GLOBAL sql_slave_skip_counter = 0,否则某条事务被跳过会导致后续所有 chunk 校验失效,但错误日志里只显示“checksum mismatch”,不提示跳过原因 - 对无主键/无唯一键表,默认跳过校验;若必须校验,需加
--chunk-index指定一个非空且高基数的字段(如created_at),否则会因分片失败而中断
抽样 MD5 比对时字段拼接的坑比想象中多
直接 SELECT MD5(CONCAT(*)) 是典型反模式,MySQL 对 NULL、空格、字符集、时区的处理会让哈希值完全失真:
- 必须显式列出字段,并用
COALESCE(col, '')统一NULL表示,避免CONCAT('a', NULL, 'b')返回NULL - 金额类字段要先转成字符串再拼接:
CAST(amount AS CHAR),防止浮点精度丢失(如99.9在不同库可能存为99.90000000000001) - 时间字段统一转为 UTC + 秒级精度:
UNIX_TIMESTAMP(CONVERT_TZ(created_at, @@session.time_zone, '+00:00')),避免源库在 CST、目标库在 UTC+8 下同一时刻生成不同哈希 - JSON 字段必须先
JSON_COMPACT()(MySQL 8.0+)或REPLACE(REPLACE(json_col, ' ', ''), '\n', '')去除空白,否则格式化差异直接导致哈希不等
校验期间业务写入是否允许?取决于校验类型
不是“能跑就行”,而是要匹配你的迁移阶段和风险承受力:
- 独立校验(如手动跑
pt-table-checksum或自写脚本):要求源库和目标库都处于**静态状态**——即迁移已停止、无任何 DML 写入。否则校验过程中新数据写入会污染 chunk 分片边界,导致部分行被重复计算或遗漏 - 内置校验(DTS 控制台发起):允许源库有 DML,但**严禁 DDL**;一旦在源库执行
ALTER TABLE,DTS 可能解析失败并跳过该表,而控制台日志只报“校验完成”,不提示“某表未参与” - 真正准实时校验(如割接前最后 5 分钟):只能靠 binlog 位点对齐 +
SELECT @@global.gtid_executed比对,再辅以关键业务单据号(如订单 ID)的端到端查询验证,而不是依赖任何“全表扫描类”校验
最容易被忽略的是:校验通过后,如果目标库开启了 innodb_strict_mode=OFF 或字符集为 utf8(而非 utf8mb4),某些宽字符插入会静默截断,但 pt-table-checksum 和 MD5 都检测不到——这类问题只能靠上线后 24 小时内监控 Aborted_clients、Warnings 和应用层字段长度断言来暴露。


















