MySQL 备份到底能不能恢复:一个可下载的演练脚本(mysqldump → 临时库 → 逐表比对)
下载可直接运行的 bash 脚本:mysqldump 备份、恢复到临时库、逐表 count(*) 比对,输出 CSV 证据后自动删除临时库。附 MySQL 8.0.46 实测结果与两个真实踩坑。
“有备份”不等于“能恢复”。这个脚本把一次恢复演练压缩成一条命令,并留下备份大小、备份/恢复耗时、逐表行数比对三类证据。
适用对象
- 演练产出是 summary.csv 和 compare.csv,可以直接作为恢复演练记录归档。
- 脚本对源库只读,但会在同一实例创建并删除临时库,需要 CREATE 权限和足够磁盘。
- 逐表 count(*) 只证明“行都回来了”,不证明业务正确;关键表建议再补抽样校验。
- mysqldump 是逻辑备份,不能替代基于 binlog 的时间点恢复(PITR)。
一条命令怎么跑
连接参数走 mysql 客户端惯例:`MYSQL_HOST=10.0.0.5 MYSQL_TCP_PORT=3306 MYSQL_USER=dba MYSQL_PWD=*** ./mysql-backup-restore-drill-v1.0.sh shop /data/drill/2026-10-15`。第二个参数是证据目录,不填就在当前目录建 `drill-时间戳`。密码建议放 `~/.my.cnf`,不要写进命令行历史。
建议在从库或专门的演练实例上跑:恢复会占用接近源库大小的磁盘,count(*) 在大表上会扫全表。脚本用 `trap` 保证无论成功失败都删除临时库,临时库名是 `<源库>_restore_drill_<时间戳>`。
测试库上的输出
summary.csv:dump_bytes=1403355(约 1.4MB)、dump_seconds=0、restore_seconds=3、tables_compared=3、tables_diff=0、result=PASS,mysql_version=8.0.46。compare.csv 三行都是 OK:order_items 0/0,orders 200000/200000,users 1000/1000。
测试库太小,耗时没有参考意义。你自己库上的 restore_seconds 才是关键数字:拿它和业务能接受的停机时间(RTO)比。如果恢复要 3 小时而 RTO 是 1 小时,就该评估物理备份、常备只读副本,或分库分表后的并行恢复。
| 文件 | 内容 | 用途 |
|---|---|---|
| summary.csv | 备份大小、备份/恢复秒数、比对表数、差异表数、PASS/FAIL、版本 | 演练记录、RTO 对比 |
| compare.csv | 每张表的源库行数、恢复后行数、是否一致 | 定位缺失表或行数差异 |
| src_counts.csv / restored_counts.csv | 两侧原始行数 | 复核 |
| <源库>.sql.gz | 本次逻辑备份 | 可保留作为一份已验证可恢复的备份 |
这次实测里我踩到的两个坑
脚本第一版在我这台机器上连续 FAIL,原因都写进了现在的版本:
本节判断
- 主机装的是 MariaDB 客户端时,`mysqldump --set-gtid-purged=OFF` 会直接报 unknown variable。脚本现在会先探测该选项是否存在,没有就跳过;你这边请尽量用与服务器同系列的 MySQL 8 客户端。
- 逐表 count 时如果把 `mysql` 放进管道/`while read` 循环,客户端会吞掉 stdin,结果只比对了第一张表就结束,还显示 PASS。现在每次调用都加了 `</dev/null`。你如果改脚本,记得保留这行。
- 源库在备份期间持续写入:`--single-transaction` 拿的是开始时刻的一致性视图,之后再 count(*) 可能略多。从库或低峰跑更干净。
- 账号缺 CREATE 权限、磁盘不足、或恢复时报字符集/定义冲突——这些 FAIL 恰恰说明换机器恢复会出问题,值得在演练里暴露。
多久演练一次
我的建议是每月一次固定演练,加上每次大版本升级、迁移或备份策略变更后各一次。把 summary.csv 按月份归档,半年后就能看到恢复耗时随数据量怎么涨,什么时候该换方案一目了然。
参考依据
以下来源用于确认市场趋势、政策背景和术语边界;具体落地方案仍以客户的数据范围、权限和交付目标为准。
常见问题
可以在生产主库上直接跑吗?
技术上可以,脚本对源库只读,但备份和 count(*) 都会占 IO,并且会在同一实例创建临时库。建议从库或低峰执行,并先确认磁盘余量至少等于源库大小。
我们用的是物理备份(XtraBackup / 快照),这个脚本有用吗?
思路一样,但恢复步骤不同:物理备份要恢复成独立实例再比对。比对部分(count_rows)可以直接复用。
count(*) 一致就说明恢复成功了吗?
只能说明行都回来了。建议对核心表再加抽样比对,例如按主键取最近 1000 行做校验和。