人生若只如初见

WXY

MySQL 数据恢复:使用 ibd2sql 工具从 IBD 文件中恢复数据的完整指南

2024-07-24

ibd2sql 是一款强大的 MySQL 数据恢复工具,能够从 .ibd 文件中提取数据并生成 .sql 文件,帮助用户在数据丢失和数据库损坏时有效恢复数据。尽管在某些方面有局限性,但其简单易用的特点使得它成为处理 MySQL 数据库问题时的得力助手。通过本文的介绍,希望你能更好地理解和应用 ibd2sql,为你的数据库管理工作提供支持。

ibd2sql是一个使用纯python3编写的离线解析MYSQL INNODB存储引擎的ibd文件的工具. 无第三方依赖包. 使用GPL-3.0 license.

特点

  1. 方便: 提取表DDL

  2. 实用: 可替换库(--schema)/表(--table)名, 可在sql语句中输出完整的字段(--complete)

  3. 简单: 纯python3代码编写, 无依赖包.

  4. 支持众多数据类型: 支持所有mysql数据类型

  5. 支持复杂的表结构: 分区表, 注释, 主键, 外键, 约束, 自增, 普通索引, 前缀索引, 主键前缀索引, 唯一索引, 复合索引, 默认值, 符号, 虚拟字段, INSTANT, 无主键等情况的表

  6. 数据误删恢复: 可以输出被标记为deleted的数据

  7. 安全: 离线解析ibd文件, 仅可读权限即可

  8. 支持范围广: 支持mysql 5.6 or 5.7 or 8.0 or 8.4 or 9.0

下载

wget https://github.com/ddcw/ibd2sql/archive/refs/heads/main.zip
unzip main.zip
cd ibd2sql-main

要求和支持范围

要求: python3

支持范围: mysql5.x 8.x 9.x

简单使用

本工具使用纯python3编写, 无依赖包, 所以建议直接使用源码.

Linux

python3 main.py /data/mysql_3314/mysqldata/ibd2sql/ddcw_alltype_table.ibd --sql --ddl

Windows

注意python名字和路径

python main.py F:\t20240627\test\ddcw_char_ascii.ibd --sql --ddl

若要将结果保存到文件, 可使用重定向(python3 main.py xxx.ibd --sql > xxxx.sql)

参数说明

SHELL>python3 main.py --help

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

FILENAME 目标文件, 即要解析的ibd文件

--help 仅打印帮助信息,不做任何操作

--version 仅展示版本信息, 不做任何操作

--ddl 打印目标文件的DDL信息.

--sql 打印目标文件的数据, 并拼接为SQL语句

--delete 打印目标文件被标记为deleted的数据, 需要和--sql联合使用.

--complete-insert 打印的SQL语句更完整, 即增加字段信息(某些数据库需要字段信息)

--force 对于某些可能报错的场景可以使用此选项跳过. 目前无实际使用场景.

--set 本来是对set/enum的值取int还是实际值, 现默认启用. 故此参数无效

--multi-value 对于生成的INSERT语句, 按照每页作为一个SQL语句. 即insert into table values(),(),();

--replace 使用replace语句代替insert语句. 和--multi-value冲突

--table 使用指定的表名替代元数据信息中的表名.

--schema 使用指定的库名替代元数据中的库名.

--sdi-table 指定元数据表文件. 对于5.x和分区表这种元数据信息不在指定的目标文件中, 则需要单独指定元数据文件.

--where-trx 指定事务范围. 默认(0,281474976710656)

--where-rollptr 指定回滚指针范围. 默认(0,72057594037927936)

--limit 仅打印N行数据. 同DML中的limit.

--debug 使用DEBUG功能, 会生成大量的解析日志信息.

--debug-file 当启用debug功能时, 可使用此选项指定debug日志文件. 默认stdout

--page-min 如果正在解析的页号小于这个值, 则跳过该页.

--page-max 如果正在解析的页号大于这个值, 则跳过.

--page-start 指定第一个数据页(叶子节点). 方便跳过坏块.

--page-count 解析的页数量. 通常和--page-start联合使用.

--page-skip 跳过的页数量.

--mysql5 如果是mysql 5.6/5.7 除了指定--sdi-table选项外, 还应指定这个选项, 方便ibd2sql失败为mysql5的数据文件.

使用例子

为了方便展示, 如下使用xxx.ibd文件来代替实际的ibd文件, 实际解析的时候需要 相对/绝对路径.

未特别说明的场景, 均是指mysql 8.x环境.

解析出表结构(DDL)

python3 main.py xxx.ibd --ddl

解析出数据(DML)

python3 main.py xxx.ibd --sql

解析表数据(DDL+DML)

python3 main.py xxx.ibd --ddl --sql

解析被误删的数据

python3 main.py xxx.ibd --sql --delete

分区表解析

分区表需要指定元数据信息

python3 main.py /data/mysql_3314/mysqldata/ibd2sql/ddcw_partition_range#p#p1.ibd --sql --sdi-table /data/mysql_3314/mysqldata/ibd2sql/ddcw_partition_range#p#p0.ibd

5.6 & 5.7

如果是mysql5.6或者5.7, 则需要先使用mysqlfrm提取元数据信息并写入到mysql8.0的环境中, 以供ibd2sql获取元数据信息.

# 提取出DDL 
mysqlfrm /data/mysql_3308/mysqldata/db1/ddcw_alltype_table.frm --diagnostic 

# 然后导入到8.0环境(以获取SDI信息.)
....

# 就可以使用本工具解析了
python3 main.py --sdi-table /data/mysql_3314/mysqldata/ibd2sql/ddcw_alltype_table.ibd /data/mysql_3308/mysqldata/db1/ddcw_alltype_table.ibd  --sql --mysql5

注: mysqlfrm 存在 timestamp等数据类型的精度丢失问题. 需要人工确认. 如果可以直接从数据库里面获取元数据信息更好.

ibd文件损坏的场景

如果ibd文件数据页损坏, 则可以跳过该页, 或者暴力解析.

对于想并发解析的, 也可以使用本方法.

如果是ibd文件的元数据信息损坏, 则要先恢复元数据信息. 然后使用--sdi-table选项指定正确的元数据信息文件.

我这里没有做重定向, 是直接打印在屏幕上的(方便演示)

filename="/tmp/ddcw_alltype_table.ibd" # 要解析的ibd文件名
python3 main.py ${filename} --ddl # 获取表结构信息
filesize=`stat -c %s ${filename}`
maxpagecount=$[ ${filesize} / 16384 ]
current_page=1
while [ ${current_page} -le ${maxpagecount} ];do
	echo "-- ${filename} PAGE NO: ${current_page}"; 
	current_page=$[ ${current_page} + 1 ]
	python3 main.py ${filename} --sql --page-start ${current_page} --page-count 1 2>/dev/null ; 
done

如使用过程中遇到问题可以到issues 中查看有没有类似的问题以及解决方案,也欢迎在本文章中评论进行交流和学习!

完整测试结果

https://github.com/ddcw/ibd2sql/blob/main/docs/ALLTEST.md

版本更新日志

https://github.com/ddcw/ibd2sql/blob/main/docs/CHANGELOG.md

Github

https://github.com/ddcw/ibd2sql