写点什么

工具分享 - 从 ibd 文件中恢复数据的神器 ibd2sql

作者:GreatSQL
  • 2025-06-13
    福建
  • 本文字数:6523 字

    阅读完需:约 21 分钟

工具分享-从 ibd 文件中恢复数据的神器 ibd2sql

1. ibd2sql 的使用场景

在单节点单表表空间损坏的情况下,一般我们想到的方法是从最近的备份中恢复表数据并从 Binlog 中合并数据。

假如备份和 Binlog 缺失,那就只能从 ibd 文件中紧急恢复数据,可以使用 ibd2sql 这个工具去恢复数据。

2. ibd2sql 简介

ibd2sql is tool of transform mysql ibd file to sql(data).

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

3. 实测

3.1 环境信息

操作系统:ky10.x86_64

数据库版本:GreatSQL-8.0.32-27

3.2 数据库安装并初始化数据

GreatSQL 安装参考:https://greatsql.cn/docs/8.0.32-27/3-quick-start/3-2-quick-start-with-tarball.html

--创建测试库CREATE database test;--创建测试表CREATE TABLE `test`.`workflow_state` (  `id` int NOT NULL AUTO_INCREMENT,  `creator` varchar(64) DEFAULT NULL,  `create_at` datetime(6) NOT NULL,  `update_at` datetime(6) NOT NULL,  `updated_by` varchar(64) DEFAULT NULL,  `end_at` datetime(6) DEFAULT NULL,  `is_deleted` tinyint(1) NOT NULL,  `name` varchar(64) NOT NULL,  `desc` varchar(64) DEFAULT NULL,  `type` varchar(32) NOT NULL,  `processors_type` varchar(32) NOT NULL,  `processors` varchar(255) DEFAULT NULL,  `distribute_type` varchar(32) NOT NULL,  `notify_rule` varchar(32) NOT NULL,  `notify_freq` int NOT NULL,  `fields` longtext,  `extras` varchar(1000) DEFAULT NULL,  `is_draft` tinyint(1) NOT NULL,  `is_builtin` tinyint(1) NOT NULL,  `workflow_id` int NOT NULL,  `is_terminable` tinyint(1) NOT NULL,  `followers` varchar(255) DEFAULT NULL,  `followers_type` varchar(32) NOT NULL,  `api_instance_id` int DEFAULT NULL,  `assignors` longtext DEFAULT (_utf8mb3''),  PRIMARY KEY (`id`),  KEY `workflow_state_workflow_id_ef53cea4_fk_workflow_workflow_id` (`workflow_id`),  KEY `workflow_state_is_deleted_37d5c517` (`is_deleted`)) ENGINE=InnoDB;--插入初始化数据INSERT INTO `test`.`workflow_state` VALUES (1, 'admin', '2025-4-28 10:0:0.0', '2025-4-28 10:0:0.0', NULL, NULL, 0, '审批节点1', '基础审批流程', 'approval', 'user', 'user123', 'round_robin', 'immediate', 1, '{"field1": "value1"}', '{"priority": "high"}', 0, 1, 1, 1, 'user456,user789', 'specific', 1001, '["assignor1"]');INSERT INTO `test`.`workflow_state` VALUES (10, 'system', '2025-4-28 10:45:0.0', '2025-4-28 10:45:0.0', NULL, NULL, 0, '子流程', '调用子工作流', 'subflow', 'system', NULL, 'direct', 'immediate', 1, '{"subflow_id": 100}', '{"parameters": "{}"}', 0, 1, 10, 1, NULL, 'none', 1006, '[]');
复制代码

3.3ibd2sql 下载使用

-- 安装python3yum -y install python3-- 下载ibd2sql,没法通过wget下载,可以直接复制网址到浏览器下载wget https://github.com/ddcw/ibd2sql/archive/refs/heads/main.zip-- 解压unzip ibd2sql-main.zip-- 进入ibd2sqlcd ibd2sql-main
复制代码

3.3.1 尝试对 workflow_state 表进行表结构恢复

-- 恢复表结构,后面带的 --ddl为生成表结构$ python3.7 main.py /greatsql/dbdata/data3306/data/test/workflow_state.ibd --sql --ddlCREATE TABLE IF NOT EXISTS `test`.`workflow_state`(    `id` int NOT NULL AUTO_INCREMENT,    `creator` varchar(64) NULL,    `create_at` datetime(6) NOT NULL,    `update_at` datetime(6) NOT NULL,    `updated_by` varchar(64) NULL,    `end_at` datetime(6) NULL,    `is_deleted` tinyint(1) NOT NULL,    `name` varchar(64) NOT NULL,    `desc` varchar(64) NULL,    `type` varchar(32) NOT NULL,    `processors_type` varchar(32) NOT NULL,    `processors` varchar(255) NULL,    `distribute_type` varchar(32) NOT NULL,    `notify_rule` varchar(32) NOT NULL,    `notify_freq` int NOT NULL,    `fields` longtext NULL,    `extras` varchar(1000) NULL,    `is_draft` tinyint(1) NOT NULL,    `is_builtin` tinyint(1) NOT NULL,    `workflow_id` int NOT NULL,    `is_terminable` tinyint(1) NOT NULL,    `followers` varchar(255) NULL,    `followers_type` varchar(32) NOT NULL,    `api_instance_id` int NULL,    `assignors` longtext NULL DEFAULT (_utf8mb3''),    PRIMARY KEY  (`id` ),    KEY `workflow_state_workflow_id_ef53cea4_fk_workflow_workflow_id` (`workflow_id` ),    KEY `workflow_state_is_deleted_37d5c517` (`is_deleted` )) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ;
复制代码

3.3.2 尝试对 workflow_state 表进行表数据恢复

-- 恢复表数据,后面带的 --sql把数据转换为sql,也可以使用--complete-insert合并insert$ python3.7 main.py /greatsql/dbdata/data3306/data/test/workflow_state.ibd --sqlINSERT INTO `test`.`workflow_state` VALUES (1, 'admin', '2025-4-28 10:0:0.0', '2025-4-28 10:0:0.0', NULL, NULL, 0, '审批节点1', '基础审批流程', 'approval', 'user', 'user123', 'round_robin', 'immediate', 1, '{"field1": "value1"}', '{"priority": "high"}', 0, 1, 1, 1, 'user456,user789', 'specific', 1001, '["assignor1"]');INSERT INTO `test`.`workflow_state` VALUES (10, 'system', '2025-4-28 10:45:0.0', '2025-4-28 10:45:0.0', NULL, NULL, 0, '子流程', '调用子工作流', 'subflow', 'system', NULL, 'direct', 'immediate', 1, '{"subflow_id": 100}', '{"parameters": "{}"}', 0, 1, 10, 1, NULL, 'none', 1006, '[]');
复制代码

3.3.3 更多使用方法

可以使用--help 查看完整的使用方法,在表空间损坏的情况下可以通过--force, -f 强制调用 ibd 文件拯救数据

--help详情$ python3.7 main.py --helpusage: 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]               [--keyring-file KEYRING_FILE]               [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 --keyring-file KEYRING_FILE, -k KEYRING_FILE keyring filenameExample:ibd2sql /data/db1/xxx.ibd --ddl --sqlibd2sql /data/db1/xxx.ibd --delete --sqlibd2sql /data/db1/xxx#p#p1.ibd --sdi-table /data/db1/xxx#p#p0.ibd --sqlibd2sql /mysql57/db1/xxx.ibd --sdi-table /mysql80/db1/xxx.ibd --sql --mysql5
复制代码

3.3.4 修改 lower_case_table_names

lower_case_table_names 是 MySQL 设置大小写是否敏感的一个参数。

lower_case_table_names = 0 表名存储为给定的大小和比较是区分大小写的lower_case_table_names = 1 表名存储在磁盘是小写的,但是比较的时候是不区分大小写lower_case_table_names = 2 表名存储为给定的大小写但是比较的时候是小写的
复制代码

通常我们在数据库初始化的时候就已经确定这个参数,想要修改这个参数只能导出重新初始化再导入。

但是 ibd2sql 号称可以直接修改lower_case_table_names,请各位看官老爷往下看。

lower_case_table_names 由 0 改成 1,对象中已经有大小写混合,可以启动但是原本大小写混合对象读写会有问题

CREATE TABLE IF NOT EXISTS `test`.`TMst`(    `id` int NOT NULL AUTO_INCREMENT,    `creator` varchar(64) NULL,    `updated_by` varchar(64) NULL,    `end_at` datetime(6) NULL,    PRIMARY KEY  (`id` )) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ;INSERT INTO test.TMst (creator) VALUES ('user2');INSERT INTO test.TMst (creator) VALUES ('user1');--查看原来的lower_case_table_names为1还是0$ python3 modify_lower_case_table_names.py /greatsql/dbdata/data3306/data/mysql.ibd lower_case_table_names: 0--停止数据库$ systemctl stop greatsql--修改lower_case_table_names为1$ python3 modify_lower_case_table_names.py /greatsql/dbdata/data3306/data/mysql.ibd ./mysql.ibd 1set lower_case_table_names=1 into new file(./mysql.ibd) finish.--对比文件权限属主$ ls -la ./mysql.ibd -rw-r--r-- 1 root root 26214400 Apr 29 10:58 ./mysql.ibd$ ls -la /greatsql/dbdata/data3306/data/mysql.ibd-rw-r----- 1 greatsql greatsql 26214400 Apr 29 10:56 /greatsql/dbdata/data3306/data/mysql.ibd--修改文件属主$  chmod 640 ./mysql.ibd$  chown greatsql:greatsql ./mysql.ibd  -- 覆盖原来的mysql.ibd文件$ mv ./mysql.ibd /greatsql/dbdata/data3306/datamv: overwrite '/greatsql/dbdata/data3306/data/mysql.ibd'? y--修改配置文件 lower_case_table_names=1$ vi /greatsql/conf/greatsql3306.cnf --启动数据库$ systemctl start greatsql--查询表,插入数据报错greatsql> show tables;+----------------+| Tables_in_test |+----------------+| TMst           |+----------------+1 row in set (0.01 sec)
greatsql> SELECT * FROM TMst;ERROR 1146 (42S02): Table 'test.tmst' doesn't exist
greatsql> INSERT INTO test.TMst (creator) VALUES ('user3');ERROR 1146 (42S02): Table 'test.tmst' doesn't exist

greatsql> DROP database test;greatsql> CREATE database test;ERROR 3678 (HY000): Schema directory './test' already exists. This must be resolved manually (e.g. by moving the schema directory to another location).
复制代码

lower_case_table_names 由 1 改成 0,对象读写正常

create database test1;CREATE TABLE IF NOT EXISTS `test1`.`tmst`(    `id` int NOT NULL AUTO_INCREMENT,    `creator` varchar(64) NULL,    `updated_by` varchar(64) NULL,    `end_at` datetime(6) NULL,    PRIMARY KEY  (`id` )) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ;INSERT INTO test1.tmst (creator) VALUES ('user2');INSERT INTO test1.tmst (creator) VALUES ('user1');--查看原来的lower_case_table_names为1还是0$ python3 modify_lower_case_table_names.py /greatsql/dbdata/data3306/data/mysql.ibd lower_case_table_names: 1--停止数据库$ systemctl stop greatsql--修改lower_case_table_names为1$ python3 modify_lower_case_table_names.py /greatsql/dbdata/data3306/data/mysql.ibd ./mysql.ibd 0set lower_case_table_names=0 into new file(./mysql.ibd) finish.--对比文件权限属主$ ls -la ./mysql.ibd -rw-r--r-- 1 root root 26214400 Apr 29 10:58 ./mysql.ibd$ ls -la /greatsql/dbdata/data3306/data/mysql.ibd-rw-r----- 1 greatsql greatsql 26214400 Apr 29 10:56 /greatsql/dbdata/data3306/data/mysql.ibd--修改文件属主$  chmod 640 ./mysql.ibd$  chown greatsql:greatsql ./mysql.ibd  -- 覆盖原来的mysql.ibd文件$ mv ./mysql.ibd /greatsql/dbdata/data3306/datamv: overwrite '/greatsql/dbdata/data3306/data/mysql.ibd'? y--修改配置文件 lower_case_table_names=1$ vi /greatsql/conf/greatsql3306.cnf --启动数据库$ systemctl start greatsql--查询表,新建带有大写的表均正常greatsql> CREATE TABLE IF NOT EXISTS `test1`.`TMst`(    ->     `id` int NOT NULL AUTO_INCREMENT,    ->     `creator` varchar(64) NULL,    ->     `updated_by` varchar(64) NULL,    ->     `end_at` datetime(6) NULL,    ->     PRIMARY KEY  (`id` )    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ;Query OK, 0 rows affected (0.01 sec)
greatsql> INSERT INTO test1.TMst (creator) VALUES ('user2');Query OK, 1 row affected (0.02 sec)
greatsql> INSERT INTO test1.TMst (creator) VALUES ('user1');Query OK, 1 row affected (0.01 sec)
greatsql> SELECT * FROM `test1`.`TMst`;+----+---------+------------+--------+| id | creator | updated_by | end_at |+----+---------+------------+--------+| 1 | user2 | NULL | NULL || 2 | user1 | NULL | NULL |+----+---------+------------+--------+2 rows in set (0.00 sec)
greatsql> SELECT * FROM `test1`.`tmst`;+----+---------+------------+--------+| id | creator | updated_by | end_at |+----+---------+------------+--------+| 1 | user2 | NULL | NULL || 2 | user1 | NULL | NULL |+----+---------+------------+--------+2 rows in set (0.01 sec)
复制代码

结论

  1. 修改 lower_case_table_names

  2. 由 0 改成 1,对象中已经有大小写混合,可以启动但是原本大小写混合对象读写会有问题。

  3. 由 1 改成 0,对象读写正常,操作名字大小混合的对象也正常。

参考文章

  1. GreatSQL 二进制安装:https://greatsql.cn/docs/8.0.32-27/3-quick-start/3-2-quick-start-with-tarball.html

  2. ibd2sql 项目 README_zh.md https://github.com/ddcw/ibd2sql/blob/main/README_zh.md

发布于: 刚刚阅读数: 3
用户头像

GreatSQL

关注

GreatSQL社区 2023-01-31 加入

GreatSQL是由万里数据库维护的MySQL分支,专注于提升MGR可靠性及性能,支持InnoDB并行查询特性,是适用于金融级应用的MySQL分支版本。 社区:https://greatsql.cn/ Gitee: https://gitee.com/GreatSQL/GreatSQL

评论

发布
暂无评论
工具分享-从ibd文件中恢复数据的神器ibd2sql_GreatSQL_InfoQ写作社区