备份文件可能损坏,需先用mysqlcheck、zcat/gzcat或head命令验证完整性;若gzip报crc Error则已损坏;应恢复到临时库比对行数和校验和,不可直接覆盖生产库。

备份文件本身是否损坏?用 mysqlcheck 或 zcat/gzcat 快速探针
直接解压或导入前,先确认备份文件没在传输或磁盘写入时出错。如果是 mysqldump 生成的 SQL 文件(尤其带 --single-transaction),可用 head -n 20 backup.sql 看开头是否有 CREATE table 或注释头;如果是 gzip 压缩包,运行:
zcat backup.sql.gz | head -n 10
,能正常输出即说明 gzip 层无损。若报 gzip: invalid compressed data--crc error,说明文件已损坏,别往下试了。
恢复到临时库再比对表行数和校验和,别直接覆盖生产库
在测试环境或同一 MySQL 实例上建新库(如 restore_test),然后导入:
mysql restore_test < backup.sql
(或用 zcat backup.sql.gz | mysql restore_test)。导入后立刻执行:
-
select table_name, table_rows FROM information_schema.tables WHERE table_schema = 'restore_test';与原库information_schema.tables对比行数(注意:MyISAM 准确,InnoDB 是估算值,需另法验证) - 对关键小表(如用户配置表),跑
CHECKSUM TABLE user_config;,再在原库执行同样语句,比对返回的Checksum值是否一致 - 对大表,抽样查主键范围:
SELECT MIN(id), MAX(id), count(*) FROM orders;,两边数值应完全匹配
遇到 ERROR 1062 Duplicate entry 或乱码,说明备份时没设好字符集
这类错误往往不是数据丢了,而是备份/恢复过程编码不一致导致解析失败。检查三处:
- 备份命令是否加了
--default-character-set=utf8mb4(推荐,尤其含 emoji 或生僻字) - 目标库的
character_set_database和collation_database是否与原库一致(SHOW CREATE DATABASE origin_db;可查) - SQL 文件开头是否有
SET NAMES utf8mb4;—— 若没有,手动在文件第一行插入该语句再重导
忽略这点,哪怕行数对得上,中文字段也可能变成 ???? 或截断。
时间点恢复(PITR)验证必须结合 binlog 位置,不能只看 dump 文件
如果用 mysqldump --master-data=2 做了逻辑备份,它会在 SQL 文件里记录 CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=12345;。验证时,光恢复 dump 不够,还得确认从该 pos 开始的 binlog 是否可读、是否连续:
- 运行
mysqlbinlog --base64-output=decode-rows -v mysql-bin.000001 | head -30,看能否解析出有效事件 - 用
mysqlbinlog --stop-datetime="2024-05-20 10:00:00" mysql-bin.000001 | mysql restore_test模拟追加恢复,观察是否报错 - 若 binlog 被 purge 过,
SHOW BINARY LOGS;显示的最早日志名跟 dump 里记录的不一致,这次 PITR 就不可靠
实际中最容易被跳过的,是校验恢复后的索引是否完整——SHOW INDEX FROM restore_test.users; 和原库对比,缺失索引不会报错,但查询会慢得离谱。