张家界市网站建设_网站建设公司_博客网站_seo优化
2026/1/18 21:20:07 网站建设 项目流程

导读

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

原理

虽然之前讲过原理, 但还是来简单回顾回顾:
DROP TABLE是delete和insert系统表, 那么被删表之前的元数据信息就能找到, 虽然数据文件没了,但磁盘不会马上覆盖, 我们就能拿着元数据信息去磁盘找相关的PAGE.
image.png
TRUNCATE TABLE 是对系统表做的update,看不到被删表之前的元数据信息了; 5.7之前和现在元数据信息一样, 无所谓, 8.0的话就只能使用排除法了, 即排除有主的page,剩下的再一个个试.

可能有很多小伙伴关心: 怎么判断是需要的page呢?
从磁盘读N个块,然后判断是否是page,是否是index page,是否页校验通过… 大概如下:
image.png

现在来看看ibd2sql该怎么使用才能恢复数据
流程就是上面的从系统表提取元数据信息, 然后再扫描磁盘匹配即可. 当然每一步都是可以拆开的.
image.png
看着头都大了. 我们直接实践吧.

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

恢复被drop的表

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

这里使用的是5.7的环境; 如果是你是mysql 8.0环境, 请将 ibdata1换成mysql.ibd 其它不变

场景1: 直接恢复

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

-- 查看表数据,方便验证 
select * from t20260108_101;
-- 直接drop
drop table t20260108_101;

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

python3 main.py /data/mysql_5744/mysqldata/ibdata1 --scan /dev/vdb --sql

image.png
是不是嘎嘎简单?

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

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

python3 main.py /data/mysql_5744/mysqldata/ibdata1 --scan  --ddl

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

python3 main.py /data/mysql_5744/mysqldata/ibdata1 --scan /dev/vdb --set table=t20260108_101

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

python3 main.py /data/mysql_5744/mysqldata/ibdata1 --scan ./ibd2sql_auto_dir_20260108_155924 --sql

image.png

场景3 全都要

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

python3 main.py --scan /dev/vdb --set indexid=0,all --parallel 8

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

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

image.png

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

恢复被truncate的表

mysql 5.7恢复被truncate的表

truncate相当于drop+create, drop的数据很快会被重写, 所以我们整个大点的表.
image.png
然后我们找下相关表的tableid值为62
image.png
再根据tableid去找indexid,值为62(这里和table_id巧合的重合了…)
image.png
然后我们扫描indexid=62的page

python3 main.py --scan /dev/vdb --set indexid=62

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

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

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

8.0 恢复被truncate的表

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

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

先准备环境, 这次就200W数据吧.
image.png
扫描所有page

python3 main.py --scan /dev/vdc --set indexid=0,all

image.png

然后我们排除下已有的Indexid
image.png

可以简单使用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

image.png
还有85个, 就一个个试呗… 当然了, 还可以看下大小, 太小的也可以排除. 我这块盘就一个大表, 所以直接就定位到了. 然后解析下数据:
image.png
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

转自

https://mp.weixin.qq.com/s/chO43BISJPqz9T9auLnCOA

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询