首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[MYSQL] 使用undrop-for-innodb和ibd2sql恢复mysql 8.0环境被drop的表

[MYSQL] 使用undrop-for-innodb和ibd2sql恢复mysql 8.0环境被drop的表

原创
作者头像
大大刺猬
发布2025-09-13 13:36:25
发布2025-09-13 13:36:25
190
举报
文章被收录于专栏:大大刺猬大大刺猬

导读

日常运维中, 难免遇到某些表不小心被drop的场景, 而恰好又没有备份? 咋办呢? 当然是跑路啦

undrop-for-innodb 是一款很NB的数据恢复工具,支持在没有备份的时候恢复被drop的表; 网上教程也很多, 但是都是针对5.6/5.7环境的, 其实这款工具也是支持MySQL 8.0环境的. 本文主要就是讲如何使用undrop-for-innodb和ibd2sql恢复mysql 8.0环境被drop的表

undrop-for-innodb原理

先来看看undrop-for-innodb的原理:

  1. 使用stream_parser提取ibdata1中的索引信息,
  2. 使用c_parser提取上述索引信息中被删除表的tableid
  3. 根据tableid使用sys_parser提取上述索引信息中的字段信息(拼接表结构),可选
  4. 根据tableid使用c_parser提取上述索引信息中的indexid
  5. 根据indexid使用stream_parser扫描磁盘获取相关索引页
  6. 根据表结构信息使用c_parser解析第五步得到的索引页.

stream_parser是扫描磁盘提取索引页的工具,支持使用-T指定要解析的索引

看起来比较啰嗦, 总结就是:解析ibdata1获取indexid,根据indexid扫描磁盘获取数据.

为了方便展示, 我们画个图:

而8.0里面的表/索引信息是放在mysql.ibd中的, 表结构信息还可以找开发提供, 而indexid部分就无法使用undrop-for-innodb了. 咋办呢?

ibd2sql

有一款名叫ibd2sql的工具可以解析ibd文件, mysql.ibd也是ibd文件, 那不就可以解析了么!

ibd2sql解析ibd文件的原理其实就是: 根据表结构一行行,一个个字段的读取ibd文件中的数据. 当然可以使用一些特殊选项来解析需要的数据.

所以我们可以把获取索引id之类的信息交给ibd2sql做, 抽取索引页的步骤给undrop-for-innodb做, 解析数据部分,两个都可以做.

恢复被drop的表

目前ibd2sql不支持根据系统表(mysql.tables,mysql.columns等)来拼接DDL, 所以DDL部分我们还得找开发要. 我这里就直接给出DDL了

软件下载与安装

undrop-for-innodb的下载安装及编译(需要先安装好mysql)

代码语言:shell
复制
# 软件下载
wget https://github.com/twindb/undrop-for-innodb/archive/refs/heads/master.zip
unzip master.zip
cd undrop-for-innodb-master

# 环境准备
yum install make gcc -y

# 编译
make
# 输出stream_parser,c_parser,innochecksum_changer 在当前目录

# 编译sys_parser (需要安装mysql, 即需要使用mysql_config)
make sys_parser
# 输出 sys_parser

# 需要libmysqlclient
ln -s /soft/mysql_3306/mysqlbase/mysql/lib/libmysqlclient.so.20 /usr/lib64/mysql/libmysqlclient.so.20
ldconfig

ibd2sql的下载

代码语言:shell
复制
yum install python3 -y
wget https://github.com/ddcw/ibd2sql/archive/refs/heads/ibd2sql-v2.x.zip
unzip ibd2sql-v2.x.zip
cd ibd2sql-ibd2sql-v2.x/

模拟drop表

数据库的安装就省略了.

本次使用8.0.43版本模拟.

代码语言:sql
复制
select @@version;
create table t20250913_test_drop(id int, name varchar(200));
insert into t20250913_test_drop values(1,'ddcw'),(2,'https://github.com/ddcw/ibd2sql'),(3,'https://github.com/twindb/undrop-for-innodb');
drop table t20250913_test_drop;

使用ibd2sql获取indexid

先根据表名获取tableid

代码语言:shell
复制
python3 main.py /data/mysql_3306/mysqldata/mysql.ibd --sql --delete --complete --set table=tables | grep t20250913_test_drop

这个id字段就是tableid, 故tableid=370

根据tableid获取主键的索引id

代码语言:shell
复制
python3 main.py /data/mysql_3306/mysqldata/mysql.ibd --sql --delete --complete --set table=indexes | grep 370

table_id为370对应的数据有个 "id=159;root=4..." 中id=159的159就是indexid; root=4中的4是root pageno, 但都被drop了, 就无法根据pageno来恢复了. 所以我们只需要indexid.

根据indexid扫描磁盘

代码语言:shell
复制
./stream_parser -f /dev/vda1 -t 50G -T 159

注意不一定能扫描出来的, 有可能被回收了, 全看运气, 所以备份是很重要的.

使用ibd2sql解析数据(二选一)

然后我们就可以使用ibd2sql解析相关数据页的数据了.

得需要相同表结构的frm/ibd文件, 且需要修改后缀.page为.ibdpython3 main.py /root/undrop-for-innodb-master/pages-vda1/FIL_PAGE_INDEX/0000000000000159.ibd --sdi /data/mysql_3306/mysqldata/db2/t20250913_test_drop.ibd --sql --set leafno=0 --set rootno=0 --force

这里解析出来数据是重复的, 是因为undrop-for-innodb扫描的页就是重复的导致的.

使用undrop-for-innodb中的c_parser解析数据(二选一)

需要构造相关的表结构

代码语言:sql
复制
-- t20250913_test_drop.sql
create table t20250913_test_drop(
id int, 
name varchar(200));

然后解析数据

代码语言:shell
复制
./c_parser -6f pages-vda1/FIL_PAGE_INDEX/0000000000000159.page -t t20250913_test_drop.sql

思考

思考1:

ibd2sql v1.x版本的时候也是支持恢复drop的表的,但原理是解析xfs文件系统, 根据Inode记录的信息去对应的磁盘构建完整的ibd文件. 这种设计限制太大了,如果inode被破坏了, 就无法恢复了. 所以ibd2sql v2.x后续版本也会根据indexid扫描磁盘文件然后尽可能的恢复数据.

对于drop的表的恢复, 和undrop-for-innodb的设计比起来,ibd2sql还是太'老实'了, 不够创新,不够胆大.

思考2:

数据是放在索引页里面的, 索引页是有索引id的; 但是对于溢出数据而言是放在溢出页(off-page)的,而溢出页是不记录索引id的, 那么应该怎么解析呢?

undrop-for-innodb的做法是每个溢出页都放在pages-vda1/FIL_PAGE_TYPE_BLOB目录下面, 解析的时候需要哪个page就去读哪个page. 但如果存在相同的pageid的溢出页时会怎么样呢?

FIL_PAGE_INDEX 目录的文件是根据indexid来的, FIL_PAGE_TYPE_BLOB目录下的文件是根据pageid来的

总结

准备使ibd2sql支持解析undrop-for-innodb碎片页的时候, 看了下undrop-for-innodb的原理, 发现其还不支持8.0环境, 故尝试使其与ibd2sql结合的效果, 还不错. 后续ibd2sql也会引进该功能(不再傻兮兮的解析文件系统了...)

根据indexid,spaceid直接扫描磁盘,然后尽可能的还原为ibd文件, 可能实现起来更简单点. 但如果目标文件很大的话, 还原出来的ibd文件也可能很大了, 即使实际数据并不算多. 道阻且长.

备份很重要!

参考:

https://github.com/twindb/undrop-for-innodb

https://github.com/ddcw/ibd2sql

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导读
  • undrop-for-innodb原理
  • ibd2sql
  • 恢复被drop的表
    • 软件下载与安装
    • 模拟drop表
    • 使用ibd2sql获取indexid
    • 根据indexid扫描磁盘
    • 使用ibd2sql解析数据(二选一)
    • 使用undrop-for-innodb中的c_parser解析数据(二选一)
  • 思考
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档