直接对比表行数是否可靠?
单纯比对
COUNT(*)在多数场景下是“假安心”——它能快速发现明显缺失或重复,但无法捕获字段值被静默篡改、NULL 与空字符串互换、时区转换导致的时间偏移等隐性损坏。尤其在 MySQL 升级(如 5.7 → 8.0)或跨引擎迁移(MyISAM → InnoDB)后,
sql_mode、默认字符集、时间类型处理逻辑变化都可能让数据“看起来一样,实际不同”。
建议作为第一轮粗筛,但必须配合更细粒度验证:
对每个表执行SELECT COUNT(*) FROM table_name,源库和目标库分别查,结果不一致立即中止后续操作 排除带
WHERE条件的统计(如软删除标记),确保比对口径完全一致 注意大表
COUNT(*)可能锁表或耗时长,可改用
SHOW TABLE STATUS中的
Rows字段作估算参考(仅限 InnoDB,且非精确值)
用 CHECKSUM TABLE 验证整表一致性
CHECKSUM TABLE是 MySQL 原生支持的轻量级校验方式,适合中小表(单表
实操要点:
执行CHECKSUM TABLE table_name,两库分别运行,比对
Checksum列数值 该命令会加读锁,生产环境避开高峰期;对大表慎用,可能引发长时间阻塞 不支持分区表全表校验(需逐个分区执行),也不校验表结构、索引、外键约束 MySQL 8.0.26+ 默认禁用该功能(
skip_checksum_table=ON),需确认配置已开启
逐行比对字段值:pt-table-checksum + pt-table-sync
Percona Toolkit 的
pt-table-checksum是生产环境最常用的方案,它将表按主键/唯一键分块,每块计算 CRC32 校验和并写入专用校验表,支持主从、跨实例、断点续传,规避了单次锁表风险。
关键配置和避坑点:
必须确保源库开启 binlog(binlog_format=ROW最佳),目标库为 source 的从库或逻辑复制下游 运行前先用
pt-table-checksum --replicate=test.checksums --no-check-binlog-format h=source_host,u=user,P=3306测试连通性和权限 校验结果存于
test.checksums表,通过
SELECT * FROM test.checksums WHERE this_crc != master_crc OR is_drift = 1查异常分块 发现差异后,用
pt-table-sync修复,但务必加
--execute
字符集与排序规则是否真正一致?
升级或迁移后最容易被忽略的是
collation层面的“隐形不一致”。例如源库用
utf8mb4_unicode_ci,目标库误配成
utf8mb4_0900_as_cs,会导致相同字符串比较结果不同,进而影响去重、排序、JOIN 结果,但
CHECKSUM和
COUNT完全无法发现。
检查方法:
查库级:SELECT DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = 'db_name'查表级:
SELECT TABLE_COLLATION FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'db_name' AND TABLE_NAME = 't1'查字段级:
SELECT COLUMN_NAME, COLLATION_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'db_name' AND TABLE_NAME = 't1' AND COLLATION_NAME IS NOT NULL特别注意
TEXT类型字段,其 collation 可能与表默认不同,且影响
GROUP BY和
ORDER BY行为
真正的完整性不是“数得上”,而是“用起来结果一致”。字符集、时区、SQL 模式、隐式类型转换规则这些底层设定,往往比某一行数据多或少更难排查。
