首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >[MYSQL] 恢复被drop/truncate的表

[MYSQL] 恢复被drop/truncate的表

原创
作者头像
大大刺猬
发布2026-01-08 17:03:12
发布2026-01-08 17:03:12
28214
举报
文章被收录于专栏:大大刺猬大大刺猬

导读

ibd2sql v2.2版本新增了恢复drop和truncate的表的功能. 这么叼? 我来瞅瞅呢

原理

虽然之前讲过原理, 但还是来简单回顾回顾:

DROP TABLE是delete和insert系统表, 那么被删表之前的元数据信息就能找到, 虽然数据文件没了,但磁盘不会马上覆盖, 我们就能拿着元数据信息去磁盘找相关的PAGE.

TRUNCATE TABLE 是对系统表做的update,看不到被删表之前的元数据信息了; 5.7之前和现在元数据信息一样, 无所谓, 8.0的话就只能使用排除法了, 即排除有主的page,剩下的再一个个试.

可能有很多小伙伴关心: 怎么判断是需要的page呢?

从磁盘读N个块,然后判断是否是page,是否是index page,是否页校验通过... 大概如下:

现在来看看ibd2sql该怎么使用才能恢复数据

流程就是上面的从系统表提取元数据信息, 然后再扫描磁盘匹配即可. 当然每一步都是可以拆开的.

看着头都大了. 我们直接实践吧.

5.7的元数据文件是ibdata1, 8.0是mysql.ibd, 请自己根据自己的版本做替换, 演示例子可能会交换着来.

恢复被drop的表

实际使用可能需要考虑很多情况, 我这里简单列出一些场景.

这里使用的是5.7的环境; 如果是你是mysql 8.0环境, 请将 ibdata1换成mysql.ibd 其它不变场景1: 直接恢复

不小心drop了一张表, 啥也不管,直接干.

代码语言:sql
复制
-- 查看表数据,方便验证 
select * from t20260108_101;
-- 直接drop
drop table t20260108_101;

然后我们扫描磁盘恢复被删除的数据:

代码语言:shell
复制
python3 main.py /data/mysql_5744/mysqldata/ibdata1 --scan /dev/vdb --sql

是不是嘎嘎简单?

场景2 存在多张表被drop的时候

实际中, 可能有多张表被删除, 我们需要先筛选一番

代码语言:shell
复制
python3 main.py /data/mysql_5744/mysqldata/ibdata1 --scan  --ddl

这里有2张表, 我们可以使用--set table来指定需要的表, 并且我们不要直接输出sql, 先输出为page (不要--sql就是输出page形式,也就是二进制文件)

代码语言:shell
复制
python3 main.py /data/mysql_5744/mysqldata/ibdata1 --scan /dev/vdb --set table=t20260108_101

然后我们再扫描上面获取的目录

代码语言:shell
复制
python3 main.py /data/mysql_5744/mysqldata/ibdata1 --scan ./ibd2sql_auto_dir_20260108_155924 --sql

场景3 全都要

磁盘下所有的index page我全都要, 主要是怕万一被覆盖了.

代码语言:shell
复制
python3 main.py --scan /dev/vdb --set indexid=0,all --parallel 8

然后再自己去找需要的page并解析. 比如我要解析ibd2sql_auto_dir_20260108_160541/index/0_0000000037_0000000000000058.page则可以使用

代码语言:shell
复制
python3 main.py ibd2sql_auto_dir_20260108_160541/index/0_0000000037_0000000000000058.page --sdi /data2/db1/t20260108_101.ibd --set leafno=0 --set rootno=0 --force --sql

5.7的ibdata1中能得到的元数据信息不多, 所以需要提供相关的表结构元数据信息, 然后使用--sdi指定即可.

恢复被truncate的表

mysql 5.7恢复被truncate的表

truncate相当于drop+create, drop的数据很快会被重写, 所以我们整个大点的表.

然后我们找下相关表的tableid值为62

再根据tableid去找indexid,值为62(这里和table_id巧合的重合了...)

然后我们扫描indexid=62的page

代码语言:shell
复制
python3 main.py --scan /dev/vdb --set indexid=62

最后我们指定sdi/frm信息去解析对于的页即可.

代码语言:shell
复制
python3 main.py ./ibd2sql_auto_dir_20260108_162317/index/0_0000000041_0000000000000062.page  --sdi /data/mysql_5744/mysqldata/db1/t20260108_105.frm --set leafno=0 --set rootno=0 --force --sql --limit 1

419W的数据量,恢复了411W 还行.

8.0 恢复被truncate的表

8.0的就有难度了, 因为truncate的表是update的系统表, 看不到truncate之前的indexid了, 而且测试发现truncate前后表的indexid是变化的, 也就是无法根据indexid直接去找了.

但也不是完全没办法:

  1. 扫描所有的page,
  2. 排除当前已使用的indexid,
  3. 从剩下得到page里面一个个试.

先准备环境, 这次就200W数据吧.

扫描所有page

代码语言:shell
复制
python3 main.py --scan /dev/vdc --set indexid=0,all

然后我们排除下已有的Indexid

可以简单使用shell筛选下:

代码语言:shell
复制
ls ./ibd2sql_auto_dir_20260108_163711/index/ | awk -F '_' '{print $NF}' | awk -F '.' '{print $1}' | sort > /tmp/t20250108_01.txt
python3 main.py /data2/mysql.ibd --set table=indexes --sql --delete with  | grep PRIMARY | awk -F ',' '{printf "%016d\n",$2}' | sort > /tmp/t20250108_02.txt
diff /tmp/t20250108_01.txt /tmp/t20250108_02.txt | grep '^<' | wc -l

还有85个, 就一个个试呗... 当然了, 还可以看下大小, 太小的也可以排除. 我这块盘就一个大表, 所以直接就定位到了. 然后解析下数据:

truncate之前是2097152条数据, 现在恢复的是2095322条数据, 就丢几千条, 还是能接受的.

总结

ibd2sql v2.2版本支持了 mysql 5.7和8.0的DROP TABLETRUNCATE TABLE的恢复, 但drop/truncate表的恢复技术只是保底的, 备份是很重要的.

本次只列出了一些用法, 更多用法可自行组合.

参考:

https://github.com/ddcw/ibd2sql/releases/tag/v2.2

软件下载地址: https://github.com/ddcw/ibd2sql/archive/refs/tags/v2.2.tar.gz

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导读
  • 原理
  • 恢复被drop的表
    • 场景2 存在多张表被drop的时候
    • 场景3 全都要
  • 恢复被truncate的表
    • mysql 5.7恢复被truncate的表
    • 8.0 恢复被truncate的表
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档