离线解析MySQL InnoDB存储引擎的IBD文件生成SQL语句恢复数据库工具-ibd2sql

ibd2sql 是一个使用纯 Python 3 编写的工具,用于离线解析 MySQL InnoDB 存储引擎的 IBD 文件,并将其转换为 SQL 语句。该工具无需任何第三方依赖包,使用 GPL-3.0 许可证发布

先看优缺点

优点

  1. 方便: 提取表的 DDL(数据定义语言)。
  2. 实用: 支持替换库名(--schema)和表名(--table),可以在 SQL 语句中输出完整的字段(--complete)。
  3. 简单: 纯 Python 3 代码编写,无依赖包。
  4. 支持众多数据类型: 支持所有 MySQL 数据类型。
  5. 支持复杂的表结构: 支持分区表、注释、主键、外键、约束、自增、普通索引、前缀索引、主键前缀索引、唯一索引、复合索引、默认值、符号、虚拟字段、INSTANT、无主键等情况的表。
  6. 数据误删恢复: 可以输出被标记为已删除的数据。
  7. 安全: 离线解析 IBD 文件,仅需读取权限。
  8. IBD文件强制解析:IBD文件如果损坏,可以恢复部分数据。
  9. 支持范围广: 支持 MySQL 5.6、5.7、8.0、8.4、9.0。

缺点

  1. 性能: 对于大型表,解析和生成 SQL 语句的过程可能较慢。
  2. 数据完整性: 如果 IBD 文件本身已经严重损坏,恢复的数据可能不完整。
  3. 资源消耗: 生成的 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

使用

Linux

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

Windows

注意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

标签: MySQL, Python

相关文章

使用Python3开发一个网站内链检查工具

1. 指定域名站点爬取与站内链接跟踪输入:指定一个域名(如https://www.lvtao.net),工具需要抓取该站点的所有页面内容。目标:递归跟踪并访问站点内的所有链接。只有同域名的站内链...

php+mysql中如何处理嵌套(子)事务并保持原子性一致

在PHP和MySQL中处理子事务并保持原子性一致性是一个复杂但非常重要的问题,尤其是在处理涉及多个数据库操作的业务逻辑时。以下是一些关键的解决方案、思路、技术要点和涉及的难点讲解。解决方案与思路...

图片Base64编码

CSR生成

图片无损放大

图片占位符

Excel拆分文件