用 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这类低级失误。
