必须分层校验结构、行级内容和业务逻辑三者缺一不可;结构比对需用mysqldump -d导出后diff并排除AUTO_INCREMENT等非关键差异,重点核查ENGINE、CHARSET/COLLATE、索引顺序及外键行为,视图存储过程需单独验证兼容性。

迁移完成后,COUNT(*)一致 ≠ 数据正确。必须分层校验:结构、行级内容、业务逻辑三者缺一不可,否则上线后订单对不上、金额差一分都是真实风险。
先比表结构,别让字段类型悄悄“变脸”
结构不一致会埋下隐性雷:比如源库 TINYINT(1) 在 RDS 8.0 上被解释为布尔,但应用层仍当整数用;或 utf8mb4_unicode_ci 和 utf8mb4_0900_as_cs 排序结果不同,导致 ORDER BY 错乱。
- 用
mysqldump -d分别导出源库和 RDS 的 DDL,再diff文本比对(注意排除AUTO_INCREMENT初始值、COMMENT等非关键差异) - 重点盯:
ENGINE(RDS 默认是 InnoDB,但旧库可能是 MyISAM)、CHARSET/COLLATE、主键/唯一索引字段顺序、外键的ON DELETE行为是否保留 - RDS 不支持某些自定义函数或插件,视图/存储过程需单独验证语法兼容性,不能只看
SHOW CREATE VIEW能执行就认为 OK
用 pt-table-checksum 做行级比对,但得绕开 RDS 限制
pt-table-checksum 是目前最可靠的跨实例行级校验工具,但它在 RDS 上不能直接当“黑盒”用——RDS 不开放 super 权限,也不允许你改 sql_slave_skip_counter,更没法把 RDS 当成从库来配复制关系。
- 必须走离线模式:
--no-check-binlog-format --replicate=percona.checksums --chunk-size=1000,且目标库需提前建好percona.checksums表(RDS 允许普通用户建表) - 无主键表会被跳过,若必须校验,加
--chunk-index=created_at(选一个非空、高基数、有索引的字段) - 执行完立刻查:
SELECT * FROM percona.checksums WHERE this_crc != master_crc OR is_drift = 1,只要有一行就说明存在真实不一致,不是误报 - 大表(>500 万行)建议在 RDS 低峰期跑,它会触发大量
SELECT,可能影响监控或慢日志采集
抽样字段 MD5 比对,手动写 SQL 时必须处理 NULL 和时区
很多团队直接 SELECT MD5(CONCAT(*)),结果发现哈希总对不上——MySQL 遇到 NULL 就整个返回 NULL,时间字段在源库 CST、RDS UTC+8 下值不同,JSON 字段空格多一个都导致哈希失效。
- 字段拼接前统一处理:
COALESCE(col, '')替换NULL,CAST(amount AS CHAR)防浮点精度漂移,UNIX_TIMESTAMP(CONVERT_TZ(created_at, @@session.time_zone, '+00:00'))强制转 UTC 秒级 - JSON 字段用
JSON_COMPACT(json_col)(MySQL 8.0+)或REPLACE(REPLACE(json_col, ' ', ''), '\n', '')去空白 - 示例(取 ID 最小的 1000 行):
SELECT id, MD5(CONCAT_WS('#', COALESCE(order_no,''), CAST(amount AS CHAR), UNIX_TIMESTAMP(CONVERT_TZ(created_at, @@session.time_zone, '+00:00')))) AS chksum FROM orders ORDER BY id LIMIT 1000,两边分别执行后比对chksum集合
业务逻辑校验不能只靠 DBA,得拉上开发一起跑真实 SQL
技术上数据一致,不代表业务可用。比如“每个用户的待支付订单数”在新旧库结果一样,但其中一条订单的 status 从 'pending' 变成了 'PENDNG'(拼写错误),聚合结果照样相等。
- 挑 5–10 条高频、带 JOIN/GROUP BY/ORDER BY 的核心 SQL,例如:
SELECT user_id, COUNT(*) FROM orders JOIN users USING(user_id) WHERE status = 'paid' GROUP BY user_id ORDER BY COUNT(*) DESC LIMIT 10 - 两边库分别执行,比对结果集的
行数 + 每行字段值 + 排序顺序(用md5sum对排序后结果文件做哈希最快) - 特别验证外键完整性:
SELECT COUNT(*) FROM orders o LEFT JOIN users u ON o.user_id = u.id WHERE u.id IS NULL,RDS 若没建外键约束,这条语句在源库返回 0、在 RDS 可能返回非零 - 上线前务必在 RDS 上用真实应用账号跑一遍权限检查:
SHOW GRANTS FOR 'app_user'@'%',RDS 默认禁用FILE、PROCESS等权限,有些老应用会依赖SELECT ... INTO OUTFILE
最容易被忽略的是字符集隐式转换和 JSON 格式化差异——它们不会报错,也不会让 COUNT(*) 或 CHECKSUM TABLE 失效,但会导致业务侧读到脏数据。校验时一定要带着具体字段、具体值、具体上下文去比,而不是只信工具返回的“OK”。


















