最直接的表级验证是比对源库和目标库的 checksum table 校验和,适用于千万行以内表;需辅以 count(*)、min/max 范围校验及手动抽样比对字段值,防范字符集、时区、精度等隐式差异。

用 CHECKSUM TABLE 快速比对表级校验和
迁移后最直接的验证方式是比对源库和目标库同一张表的校验和。MySQL 内置的 CHECKSUM TABLE 命令能生成整表数据的 CRC32 校验值,适合中小规模表(单表千万行以内)。注意它默认只校验数据行,不包含索引、AUTO_INCREMENT 值或表结构差异。
- 在源库执行:
CHECKSUM TABLE `db_name`.`table_name`; - 在目标库执行相同命令,对比返回的
Checksum数值是否一致 - 若表含浮点字段(
FLOAT/DOUBLE),因精度表现可能跨版本/平台不一致,结果可能误报不同——此时应改用逻辑校验 - 该命令会加读锁,大表执行期间影响线上查询,建议在低峰期操作或先在从库验证
用 SELECT COUNT(*) 和 SELECT MIN/MAX 验证基础行数与关键范围
这是零成本、无锁、最常被忽略的第一步。很多迁移失败其实连行数都不对,但大家直接跳进复杂校验。
- 必须比对:源库和目标库的
COUNT(*),尤其注意WHERE条件是否被意外过滤(例如 mysqldump 默认跳过INFORMATION_SCHEMA或临时表) - 对主键或时间字段执行:
SELECT MIN(id), MAX(id), COUNT(*) FROM t;—— 能快速发现截断、自增偏移、或 WHERE 条件漏写(如只导了created_at > '2023-01-01'却忘了补全) - 如果表有逻辑删除标记(如
is_deleted = 0),确认迁移脚本是否保留了该过滤逻辑
用 pt-table-checksum 做分块校验(适合大表或主从一致性检查)
当表超过千万行,CHECKSUM TABLE 太慢且锁表严重。pt-table-checksum(Percona Toolkit 提供)通过分块 + CRC32 + 主从复制机制,在不锁表前提下完成逐块校验,也适用于迁移后与原库的离线比对。
- 需在源库运行,将校验结果写入指定表(如
percona.checksums),目标库需有同名库表可写入 - 关键参数:
--chunk-size控制每块行数(默认约 1k 行),--replicate指定结果表,--no-check-binlog-format可绕过 binlog 格式限制(仅离线比对时安全使用) - 执行完后查
SELECT * FROM percona.checksums WHERE this_crc != master_crc OR is_drift != 0;—— 有结果即存在不一致 - 它依赖主键或唯一索引分块,无主键表会退化为全表扫描,慎用
手动抽样比对具体字段值(防隐式类型转换/字符集问题)
校验和或行数一致 ≠ 数据真正一致。常见坑包括:源库 utf8mb4 目标库 utf8 导致 emoji 截断、TIMESTAMP 因时区设置不同而偏移、DECIMAL 精度丢失、NULL 与空字符串混淆。
- 写一条带排序和 LIMIT 的语句,抽取头部、中部、尾部各几行:
SELECT id, name, created_at, amount FROM t ORDER BY id LIMIT 100, 10;,分别在两库执行并肉眼或脚本比对输出 - 重点检查:含中文、特殊符号、小数、时间字段的记录;主键相邻但业务上有关联的多行(比如订单+订单项)
- 用
HEX()函数看实际字节:SELECT HEX(name) FROM t WHERE id = 123;,能暴露字符集降级导致的乱码或截断
实际迁移中,最容易被跳过的其实是 COUNT(*) 和字段抽样。校验和工具再强大,也掩盖不了导出时少加了 --where 或 mysqldump 忘了 --skip-triggers 这类低级失误。










