
前言
分享一个朋友写的非常非常强大的 mysql 恢复工具,救生产环境于水深火热之中。
项目地址:https://github.com/ddcw/ibd2sql
ibd2sql是一个使用纯python3
编写的离线解析MYSQL INNODB存储引擎的ibd文件
的工具. 无第三方依赖包. 使用GPL-3.0 license.
好工具应该被更多人知道,向大佬学习!!!
特点
方便: 提取表DDL
实用: 可替换库(--schema)/表(--table)名, 可在sql语句中输出完整的字段(--complete)
简单: 纯python3代码编写, 无依赖包.
支持众多数据类型: 支持所有mysql数据类型
支持复杂的表结构: 分区表, 注释, 主键, 外键, 约束, 自增, 普通索引, 前缀索引, 主键前缀索引, 唯一索引, 复合索引, 默认值, 符号, 虚拟字段, INSTANT, 无主键等情况的表
数据误删恢复: 可以输出被标记为deleted的数据
安全: 离线解析ibd文件, 仅可读权限即可
支持范围广: 支持mysql 5.6 or 5.7 or 8.0 or 8.4 or 9.0
安装 python 3
wget https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tar.xztar -xvJf Python-3.7.0.tar.xzcd Python-3.7.0/./configure prefix=/usr/local/python3./configure --enable-optimizationsmake && make installln -fs usr/local/python3/bin/python3 usr/bin/python3ln -fs /usr/local/python3/bin/pip3 /usr/bin/pip3
安装 ibd2sql
wget https://github.com/ddcw/ibd2sql/archive/refs/heads/main.zipunzip main.zipcd ibd2sql-main
只剩个 ibd 文件怎么抢救数据
测试数据
create table testidb2sql(id int primary key,info varchar(255),text blob,key(info));insert into testidb2sql values(1,'aa','wadwaderoiohooawde12222222');insert into testidb2sql values(2,'aa','1212112121211rrrrrr');root@localhost [ddl] 18:42:16 > show create table testidb2sql;+-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| Table | Create Table |+-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| testidb2sql | CREATE TABLE `testidb2sql` (`id` int NOT NULL,`info` varchar(255) DEFAULT NULL,`text` blob,PRIMARY KEY (`id`),KEY `info` (`info`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |+-------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+1 row in set (0.00 sec)root@localhost [ddl] 19:06:02 > select * from testidb2sql;+----+------+--------------------------------------------------------+| id | info | text |+----+------+--------------------------------------------------------+| 1 | aa | 0x77616477616465726F696F686F6F617764653132323232323232 || 2 | aa | 0x31323132313132313231323131727272727272 |+----+------+--------------------------------------------------------+2 rows in set (0.00 sec)
先拷贝一个 ibd 文件的备份
cp /data/mysql_8_3306/ddl/testidb2sql.ibd /data/mysql_8_3306/ddl/testidb2sql.ibd_bak
破坏数据库
root@localhost [ddl] 18:47:37 > drop table testidb2sql;Query OK, 0 rows affected (0.02 sec)
只剩个 ibd ,拿到表结构
[root@localhost ibd2sql]# python3 main.py data/mysql_8_3306/ddl/testidb2sql.ibd_bak --ddlCREATE TABLE IF NOT EXISTS `ddl`.`testidb2sql`(`id` int NOT NULL,`info` varchar(255) NULL,`text` blob NULL,PRIMARY KEY (`id` ),KEY `info` (`info` )) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ;
对比一下,是不是没有问题。
恢复方式 1 导入表空间
先登录数据库使用表结构,把表恢复出来,将表结构先写入数据字典。
CREATE TABLE IF NOT EXISTS `ddl`.`testidb2sql`(`id` int NOT NULL,`info` varchar(255) NULL,`text` blob NULL,PRIMARY KEY (`id` ),KEY `info` (`info` )) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ;
看一下数据目录,可以看到已经生成了 ibd testidb2sql.ibd,表创建流程参考前面 ONLINE DDL 关于 ddllog 的解析。
[root@localhost ddl]# ll总用量 864-rw-r-----. 1 mysql mysql 131072 10月 21 22:42 al_ddl.ibd-rw-r-----. 1 mysql mysql 131072 10月 21 18:30 ddl.ibd-rw-r-----. 1 mysql mysql 114688 10月 22 00:03 int_test.ibd-rw-r-----. 1 mysql mysql 114688 10月 20 12:09 onlineddl.ibd-rw-r-----. 1 mysql mysql 131072 10月 23 15:21 tddl.ibd-rw-r-----. 1 mysql mysql 131072 10月 25 18:54 testidb2sql.ibd-rw-r-----. 1 root root 131072 10月 25 18:47 testidb2sql.ibd_bak
然后卸载表空间
alter table `ddl`.`testidb2sql` discard tablespace;
ddl log只有 2行
2024-10-25T18:58:57.406440+08:00 73 [Note] [MY-012485] [InnoDB] DDL log post ddl : begin for thread id : 732024-10-25T18:58:57.406595+08:00 73 [Note] [MY-012486] [InnoDB] DDL log post ddl : end for thread id : 73
可以看到 ibd 文件没了
[root@localhost ddl]# ll总用量 736-rw-r-----. 1 mysql mysql 131072 10月 21 22:42 al_ddl.ibd-rw-r-----. 1 mysql mysql 131072 10月 21 18:30 ddl.ibd-rw-r-----. 1 mysql mysql 114688 10月 22 00:03 int_test.ibd-rw-r-----. 1 mysql mysql 114688 10月 20 12:09 onlineddl.ibd-rw-r-----. 1 mysql mysql 131072 10月 23 15:21 tddl.ibd-rw-r-----. 1 root root 131072 10月 25 18:47 testidb2sql.ibd_bak
我们改个名导入一下。
[root@localhost ddl]# mv testidb2sql.ibd_bak testidb2sql.ibd
啊嘞,报错了,找不到表空间。
root@localhost [(none)] 18:58:57 > alter table `ddl`.`testidb2sql` import tablespace;ERROR 1812 (HY000): Tablespace is missing for table `ddl`.`testidb2sql`.
大家知道为什么吗?
可以看到这里:
-rw-r-----. 1 root root 131072 10月 25 18:47 testidb2sql.ibd_bak
所以大家记得务必改一下权限哦。
[root@localhost ddl]# chown mysql.mysql testidb2sql.ibd[root@localhost ddl]# ll总用量 736-rw-r-----. 1 mysql mysql 131072 10月 21 22:42 al_ddl.ibd-rw-r-----. 1 mysql mysql 131072 10月 21 18:30 ddl.ibd-rw-r-----. 1 mysql mysql 114688 10月 22 00:03 int_test.ibd-rw-r-----. 1 mysql mysql 114688 10月 20 12:09 onlineddl.ibd-rw-r-----. 1 mysql mysql 131072 10月 23 15:21 tddl.ibd-rw-r-----. 1 mysql mysql 131072 10月 25 18:47 testidb2sql.ibd
再次导入
root@localhost [(none)] 19:03:03 > select * from `ddl`.`testidb2sql`;+----+------+--------------------------------------------------------+| id | info | text |+----+------+--------------------------------------------------------+| 1 | aa | 0x77616477616465726F696F686F6F617764653132323232323232 || 2 | aa | 0x31323132313132313231323131727272727272 |+----+------+--------------------------------------------------------+2 rows in set (0.00 sec)
可以看到没有问题吧!!
厉害吧!!
恢复方式二 sql 导入
直接创建表结构,然后导入就可以了,适合小表。
[root@localhost ibd2sql]# python3 main.py data/mysql_8_3306/ddl/testidb2sql.ibd_bak --sqlINSERT INTO `ddl`.`testidb2sql` VALUES (1, 'aa', 'wadwaderoiohooawde12222222');INSERT INTO `ddl`.`testidb2sql` VALUES (2, 'aa', '1212112121211rrrrrr');
解析误删数据
这个的原理是,拿到标记为删除位的数据,触发回收机制就没救了,所以只能碰碰运气。
我们给刚才的数据删掉 1 条,不要用 delete from testidb2sql 删全部啦,触发回收就没了。
root@localhost [ddl] 19:06:02 > select * from testidb2sql;+----+------+--------------------------------------------------------+| id | info | text |+----+------+--------------------------------------------------------+| 1 | aa | 0x77616477616465726F696F686F6F617764653132323232323232 || 2 | aa | 0x31323132313132313231323131727272727272 |+----+------+--------------------------------------------------------+2 rows in set (0.00 sec)root@localhost [ddl] 19:34:40 > delete from testidb2sql where id=1;Query OK, 1 row affected (0.01 sec)
然后解析一下
python3 main.py /data/mysql_8_3306/ddl/testidb2sql.ibd --sql --delete
可以看到解析出来啦。
[root@localhost ibd2sql]# python3 main.py /data/mysql_8_3306/ddl/testidb2sql.ibd --sql --deleteINSERT INTO `ddl`.`testidb2sql` VALUES (1, 'aa', 'wadwaderoiohooawde12222222');
膜拜大佬。




