MySQL8.0数据灾难恢复之只有ibd物理文件怎么恢复数据?

前言:
        天有不测风云人有旦夕祸福,DBA做为数据守护的第一责任人,数据丢失,在生产环境中不可避免,尤其遇到NB的开发,写了个看似NB的SQL,SQL最后还忘记写where条件,一件事的发生,就是种种不可能在一起发生的巧合组成了,有时就这么巧就发生了,你说怎么办?


        今天给大家分享一个NB的开发写的一个python脚本,它就可以解决上面NB开发写的NB SQL的问题!!!
        这个软件的名字叫ibd2sql (https://github.com/ddcw/ibd2sql/archive/refs/heads/main.zip)
        ibd2sql 是使用python3 编写的 提取mysql 8.0 innodb存储引擎在磁盘上的 ibd 文件信息为SQL语句的工具.
        不需要连接数据库, 只需要对目录ibd文件有可读权限即可. 无第三方依赖包, 纯python3代码. 使用GPL-3.0 license.
        别的原理啥的,我们先不谈,现在的情况是,只有一个表的物理文件,比如test.ibd文件,要怎么通过ibd2sql来恢复里面的数据呢,且听我慢慢讲来哈!!
        ibd2sql的功能特点:
方便: 提取表DDL
实用: 可替换库(--schema)/表(--table)名, 可在sql语句中输出完整的字段(--complete)
简单: 纯python3代码编写, 无依赖包. 还可以使用**--debug**查看解析过程
选择性强: 可以根据条件过滤符合要求的数据 --where , --limit
支持众多数据类型: 支持所有mysql数据类型 (比如 int, decimal, date, varchar, char, json, binary, enum, set, blob/text, longblob,空间坐标等).
支持复杂的表结构: 分区表, 注释, 主键, 外键, 约束, 自增, 普通索引, 前缀索引, 主键前缀索引, 唯一索引, 复合索引, 默认值, 符号, 虚拟字段, INSTANT, 无主键等情况的表
数据误删恢复: 可以输出被标记为deleted的数据
安全: 离线解析ibd文件, 仅可读权限即可
支持范围广: 支持mysql 5.7 or 8.x


ibd2sql安装配置:
首先需要安装python3:
        wget https://github.com/ddcw/ibd2sql/archive/refs/heads/main.zip
        unzip main.zip
        ibd2sql-main/
        python3 main.py -h
        usage: main.py [--help] [--version] [--ddl] [--sql] [--delete]
              [--complete-insert] [--force] [--set] [--multi-value]
              [--replace] [--table TABLE_NAME] [--schema SCHEMA_NAME]
              [--sdi-table SDI_TABLE] [--where-trx WHERE_TRX]
              [--where-rollptr WHERE_ROLLPTR] [--limit LIMIT] [--debug]
              [--debug-file DEBUG_FILE] [--page-min PAGE_MIN]
              [--page-max PAGE_MAX] [--page-start PAGE_START]
              [--page-count PAGE_COUNT] [--page-skip PAGE_SKIP] [--mysql5]
              [FILENAME]


解析mysql 5.7/8.0的ibd文件 https://github.com/ddcw/ibd2sql


positional arguments:
  FILENAME              ibd filename


optional arguments:
  --help, -h            show help
  --version, -v, -V    show version
  --ddl, -d            print ddl
  --sql                print data by sql
  --delete              print data only for flag of deleted
  --complete-insert    use complete insert statements for sql
  --force, -f          force pasrser file when Error Page
  --set                set/enum to fill in actual data instead of strings
  --multi-value        single sql if data belong to one page
  --replace            "REPLACE INTO" replace to "INSERT INTO" (default)
  --table TABLE_NAME    replace table name except ddl
  --schema SCHEMA_NAME  replace table name except ddl
  --sdi-table SDI_TABLE
                        read SDI PAGE from this file(ibd)(partition table)
  --where-trx WHERE_TRX
                        default (0,281474976710656)
  --where-rollptr WHERE_ROLLPTR
                        default (0,72057594037927936)
  --limit LIMIT        limit rows
  --debug, -D          will DEBUG (it's too big)
  --debug-file DEBUG_FILE
                        default sys.stdout if DEBUG
  --page-min PAGE_MIN  if PAGE NO less than it, will break
  --page-max PAGE_MAX  if PAGE NO great than it, will break
  --page-start PAGE_START
                        INDEX PAGE START NO
  --page-count PAGE_COUNT
                        page count NO
  --page-skip PAGE_SKIP
                        skip some pages when start parse index page
  --mysql5              for mysql5.7 flag
Example:
ibd2sql /data/db1/xxx.ibd --ddl --sql
ibd2sql /data/db1/xxx.ibd --delete --sql
ibd2sql /data/db1/xxx#p#p1.ibd --sdi-table /data/db1/xxx#p#p0.ibd --sql
ibd2sql /mysql57/db1/xxx.ibd --sdi-table /mysql80/db1/xxx.ibd --sql --mysql5
        
        由于是python脚本,就不需要三板斧哈,直接使用,注意要python 3.x以上的版本  python2.x是不行的哈


数据恢复案例:这边只测试了8.0版本的数据恢复,5.7的好像不行,大家可以按作者的方法试一下,在5.7版本下,我没有验证成功
以下操作都是在MySQL8.0版本下哈


在数据库中创建表和插入数据:
use test;
CREATE TABLE `test` (
  `id` int DEFAULT NULL,
  `name` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'name'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci


插入测试数据:
 mysql> insert into test.test ( id,name) values(1,'skinfo'),(2,'skinfo'),(3,'skinfo');
Query OK, 3 rows affected (0.02 sec)
Records: 3  Duplicates: 0  Warnings: 0


查看插入的数据:
mysql> select * from test.test;
+------+--------+
| id  | name  |
+------+--------+
|    1 | skinfo |
|    2 | skinfo |
|    3 | skinfo |
+------+--------+
3 rows in set (0.00 sec)


这时再删除1条数据:
mysql> delete from test.test where id=3;
Query OK, 1 row affected (0.02 sec)


mysql> select * from test.test;
+------+--------+
| id  | name  |
+------+--------+
|    1 | skinfo |
|    2 | skinfo |
+------+--------+
2 rows in set (0.00 sec)


假设这个时间数据库宕机了,实例也无法启动了,要如何恢复test.test中的数据呢,这个时间就是ibd2sql发挥作用的时间了,哈哈。。
1.找到test.test表的物理文件,如果是rpm包安装的,在/var/lib/mysql/test这个目录下,有个叫test.ibd的文件


2.把这个文件复制到其它目录,没错,是直接复制到其它目录,数据库实例也不需要启动哈
[root@mysql8035 test]# cd /var/lib/mysql/test
[root@mysql8035 test]# pwd
/var/lib/mysql/test
[root@mysql8035 test]# ls
test.ibd
[root@mysql8035 test]# cp test.ibd /root/
[root@mysql8035 ~]# pwd
/root
[root@mysql8035 ~]# ls
test.ibd
3.运行以下的命令:
到ibd2sql目录下:
[root@mysql8035 ibd2sql-main]# pwd
/root/ibd2sql-main
[root@mysql8035 ibd2sql-main]# ls
getsql.py  ibd2sql  LICENSE  main.py  README.md  README_OLD.md
[root@mysql8035 ibd2sql-main]#


运行以下命令:
查看test表的创建语句:
 [root@node234 ibd2sql-main]# python3 ./main.py ./test.ibd --ddl
CREATE TABLE IF NOT EXISTS `test`.`test`(
    `id` int NULL,
    `name` varchar(20) NOT NULL COMMENT 'name'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ;


查看test表中已存在的数据:
[root@node234 ibd2sql-main]# python3 ./main.py ./test.ibd  --sql
INSERT INTO `test`.`test` VALUES (1, 'skinfo');
INSERT INTO `test`.`test` VALUES (2, 'skinfo');


查看test表中已删除的数据:(注意:如果表已analyze了,这个就解析不出来哈)
[root@node234 ibd2sql-main]# python3 ./main.py ./test.ibd --sql  --delete
INSERT INTO `test`.`test` VALUES (3, 'skinfo');
有上面一些数据,接入来就是导入数据库就可以了
通过ibd2sql解析出来的SQL语句跟上面操作的一样哈,数据还原回来了哈,大家可以按上面的步骤自己动手实践一下哈。。。

总结:
        ibd2sql主要用于以下数据恢复场景:
        没有备份,数据误删,文件有部分损坏等情况下可以尝试分析ibd数据文件,来恢复数据哈

分割线
感谢打赏
江西数库信息技术有限公司
YWSOS.COM 平台代运维解决方案
 评论
 发表评论
姓   名:

Powered by AKCMS