从逻辑备份中恢复单表是什么
手里只有一份整库的逻辑备份(mysqldump 的 .sql 或 mydumper 的目录),却只需要救回一张表:思路是先定位这张表在文件中的起止区间,抽取成独立片段,恢复到临时库验证无误,再决定是导入生产还是导出后合并。mydumper 的目录备份每表一个文件,定位几乎不花成本;单个大 .sql 文件则要靠注释行做边界。整库重放风险太大,能用片段解决就不要碰它。
基本信息
| 适用版本 | mysqldump / mydumper 产物通用,MySQL 5.7 / 8.0 |
|---|---|
| 区间边界 | "Table structure for table" 与 "Dumping data for table" 注释行 |
| mysqldump 产物 | 单文件,需要按行号或 awk 按表名抽取 |
| mydumper 产物 | 每表一个 .sql 文件,直接取文件即可 |
| 验证方式 | 先恢复到临时库,再比对行数、校验和 |
| 危险点 | 片段里默认带 DROP TABLE,直接导入生产会先删表 |
典型使用场景
- 误删或误改单表数据,用最近的逻辑备份定向恢复
- 表结构被意外变更,需要从备份里取回原建表语句
- 给测试环境单表数据,避免整库导入耗时与影响
- 跨库搬表:从备份片段导入另一个库或实例
- 恢复演练:验证备份文件是否可读、单表恢复流程是否可行
从 mysqldump 提取单表
从 mysqldump 提取单表
# 1) 定位表在文件中的起始行(结构与数据各有一段)
grep -n 'Table structure for table `orders`' all.sql
# 2) 按行号抽取区间(示例:1200 到 1580 行)
sed -n '1200,1580p' all.sql > orders_extract.sql
# 3) 去掉片段开头的 DROP TABLE,避免误删生产表
sed -i 's/^DROP TABLE IF EXISTS `orders`;/-- &/' orders_extract.sql
# 4) 先恢复到临时库验证,确认行数与业务数据正常
mysql -uroot -p tmp_restore < orders_extract.sql
mysql -uroot -p -e 'SELECT COUNT(*) FROM tmp_restore.orders;'用 awk 按表名自动抽区间
用 awk 按表名自动抽区间
# 抽取单表片段:从 BEFORE INSERT 标记到下一个表的注释为止
awk '/^-- Table structure for table `orders`/{flag=1} flag{print} /^-- Dumping data for table `orders`/{d=1} d&&/^-- Table structure for table `/{if(!/orders/){exit}}' all.sql > orders_extract.sql
# 抽取结果自检:首尾注释是否正确、是否包含完整 INSERT
head -5 orders_extract.sql; tail -3 orders_extract.sql抽取方式对照
| 方式 | 优点 | 风险 |
|---|---|---|
| sed 行号法 | 命令短、易上手 | 备份文件重新生成后行号全变,易抽错 |
| awk 表名匹配 | 不依赖行号,可脚本化 | 正则写错会包含相邻表内容 |
| mydumper 单表文件 | 零切分成本 | 需要备份时就是目录形式 |
| 整库重放后再导表 | 逻辑简单 | 耗时长、影响大,只在无其他办法时使用 |
恢复前先把备份文件复制一份到临时目录再操作,避免 sed -i 之类的命令误改原备份;抽取完成后用 head/tail 检查片段的首尾注释,确认区间没有越界。
mysqldump 默认在片段里写 DROP TABLE IF EXISTS:直接导入生产库会先删表再建表,如果导入中途失败,生产表就处于被删或半恢复状态。稳妥做法是先在临时库建好后用 INSERT ... SELECT 或导出后合并,且导入前对生产表做一次即时备份。