离线解析MySQL InnoDB存储引擎的IBD文件生成SQL语句恢复数据库工具-ibd2sql
ibd2sql 是一个使用纯 Python 3 编写的工具,用于离线解析 MySQL InnoDB 存储引擎的 IBD 文件,并将其转换为 SQL 语句。该工具无需任何第三方依赖包,使用 GPL-3.0 许可证发布
先看优缺点
优点
- 方便: 提取表的 DDL(数据定义语言)。
- 实用: 支持替换库名(--schema)和表名(--table),可以在 SQL 语句中输出完整的字段(--complete)。
- 简单: 纯 Python 3 代码编写,无依赖包。
- 支持众多数据类型: 支持所有 MySQL 数据类型。
- 支持复杂的表结构: 支持分区表、注释、主键、外键、约束、自增、普通索引、前缀索引、主键前缀索引、唯一索引、复合索引、默认值、符号、虚拟字段、INSTANT、无主键等情况的表。
- 数据误删恢复: 可以输出被标记为已删除的数据。
- 安全: 离线解析 IBD 文件,仅需读取权限。
- IBD文件强制解析:IBD文件如果损坏,可以恢复部分数据。
- 支持范围广: 支持 MySQL 5.6、5.7、8.0、8.4、9.0。
缺点
- 性能: 对于大型表,解析和生成 SQL 语句的过程可能较慢。
- 数据完整性: 如果 IBD 文件本身已经严重损坏,恢复的数据可能不完整。
- 资源消耗: 生成的 SQL 文件可能较大,需要足够的磁盘空间和内存。
使用
参数说明
--version, -v, -V: 显示版本信息。
--ddl, -d: 打印 DDL。
--sql: 打印数据的 SQL 语句。
--delete: 仅打印被标记为已删除的数据。
--complete-insert: 使用完整的插入语句。
--force, -f: 在遇到错误页面时强制解析文件。
--set: 用实际数据填充 set/enum 而不是字符串。
--multi-value: 如果数据属于同一页面,则使用单个 SQL 语句。
--replace: 使用 "REPLACE INTO" 替换 "INSERT INTO"(默认)。
--table TABLE_NAME: 替换表名(不包括 DDL)。
--schema SCHEMA_NAME: 替换库名(不包括 DDL)。
--sdi-table SDI_TABLE: 从这个 IBD 文件(分区表)读取 SDI 页面。
--where-trx WHERE_TRX: 事务过滤范围,默认 (0,281474976710656)。
--where-rollptr WHERE_ROLLPTR: 回滚指针过滤范围,默认 (0,72057594037927936)。
--limit LIMIT: 限制行数。
--debug, -D: 调试模式(输出非常大)。
--debug-file DEBUG_FILE: 调试输出文件,默认为 sys.stdout。
--page-min PAGE_MIN: 如果页面编号小于此值,则终止。
--page-max PAGE_MAX: 如果页面编号大于此值,则终止。
--page-start PAGE_START: 索引页面起始编号。
--page-count PAGE_COUNT: 页面计数编号。
--page-skip PAGE_SKIP: 解析索引页面时跳过某些页面。
--mysql5: 适用于 MySQL 5.7 标志。
下载
项目开源地址: https://github.com/ddcw/ibd2sql
wget https://github.com/ddcw/ibd2sql/archive/refs/heads/main.zip
unzip main.zip
cd ibd2sql-main
使用
python3 main.py /data/mysql_8.x/mysqldata/ibd2sql/ddcw_alltype_table.ibd --sql --ddl
注意python名字和路径
python main.py F:\mysql_8.x\test\ddcw_char_ascii.ibd --sql --ddl
未特别说明的场景, 均是指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_8.x/mysqldata/ibd2sql/ddcw_partition_range#p#p1.ibd --sql --sdi-table /data/mysql_8.x/mysqldata/ibd2sql/ddcw_partition_range#p#p0.ibd
5.6 & 5.7
如果是mysql5.6或者5.7, 则需要先使用mysqlfrm
提取元数据信息并写入到mysql8.0的环境中, 以供ibd2sql获取元数据信息.
# 提取出DDL
mysqlfrm /data/mysql_5.x/mysqldata/db1/ddcw_alltype_table.frm --diagnostic
# 然后导入到8.0环境(以获取SDI信息.)
....
# 就可以使用本工具解析了
python3 main.py --sdi-table /data/mysql_8.x/mysqldata/ibd2sql/ddcw_alltype_table.ibd /data/mysql_5.x/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
版权声明:本文为原创文章,版权归 全栈开发技术博客 所有。
本文链接:https://www.lvtao.net/tool/ibd2sql.html
转载时须注明出处及本声明