[MYSQL] 数据恢复, 无备份, 只剩一个 ibd 文件 怎么恢复数据?

2024年 4月 12日 62.3k 0

背景

环境: mysql 8.0

不小心删除了mysql数据目录, 但还剩个.ibd文件在. 没得备份, 没得binlog , 要恢复这个ibd文件里面的数据.

啊. 这… 先打一顿没有做备份的dba

分析

我们通常是使用备份+binlog来恢复数据, 但这次只有个孤零零的ibd文件.

我们知道mysql 8.0 的ibd文件也包含元数据信息(你问我怎么知道的?). 所以我们先恢复表结构, 再恢复数据.

恢复表结构

如果开发有相关的DDL更好. 没得的话. 我们就自己解析.

mysql 8.0的ibd文件存在sdi page 记录元数据信息的, 压缩的json格式. 我们可以使用官方自带的 ibd2sdi 解析出来这个json信息.

ibd2sdi /data/mysql_3314/mysqldata/ibd2sql/ddcw_alltype_table.ibd


但还要自己去拼接DDL, 太麻烦了.

所以我们使用其它工具来提取DDL, 这里就使用 ibd2sql 来提取(为啥使用这个呢? 因为是我写的 -_- 用起来顺手)

python3 main.py /tmp/ddcw_alltype_table.ibd --ddl

现在DDL已经提取出来了. 我们先创建个测试环境, 创建相同的库, 再使用上面的DDL去恢复相关的表结构

CREATE TABLE IF NOT EXISTS `ibd2sql`.`ddcw_alltype_table`(
`id` int NOT NULL AUTO_INCREMENT,
`int_col` int NULL,
`tinyint_col` tinyint NULL DEFAULT '1',
`smallint_col` smallint NULL,
`mediumint_col` mediumint NULL,
`bigint_col` bigint NULL,
`float_col` float NULL,
`double_col` double NULL,
`decimal_col` decimal(10,2) NULL,
`date_col` date NULL,
`datetime_col` datetime NULL,
`timestamp_col` timestamp NULL,
`time_col` time NULL,
`year_col` year NULL,
`char_col` char(100) NULL,
`varchar_col` varchar(200) NULL DEFAULT 'aa',
`binary_col` binary(10) NULL,
`varbinary_col` varbinary(20) NULL,
`bit_col` bit(4) NULL,
`enum_col` enum('A','B','C') NULL,
`set_col` set('X','Y','Z') NULL,
`josn_type` json NULL,
`newcol` varchar(200) NULL DEFAULT 'aa',
`newcol2` varchar(200) NULL DEFAULT 'aa',
`newcoldasdas2` varchar(300) NULL DEFAULT 'bbaa',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ;

恢复数据

恢复了表结构后, 就该恢复数据了.

方法1(推荐)

mysql可以使用discard table来删除表空间, 然后使用import tablespace 来导入表空间. 我们就使用这种方式来恢复数据.

官网介绍: https://dev.mysql.com/doc/refman/8.0/en/innodb-table-import.html

-- 移除表空间
alter table ddcw_alltype_table discard tablespace;

-- 拷贝要恢复的表空间
system cp -ra /tmp/ddcw_alltype_table.ibd /data/mysql_3314/mysqldata/ibd2sql

-- 导入要恢复的表空间
alter table ddcw_alltype_table import tablespace;

-- 验证数据
select count(*) from ddcw_alltype_table;

这种方法非常简单方便, 推荐使用.

但有可能会失败(人生不总是一帆风顺).

ERROR 1815 (HY000): Internal error: Cannot reset LSNs in table `dbname`.`tablename` : Data structure corruption

方法2

如果无法导入表空间的话, 我们还可以解析这个ibd文件得到相关的数据. 这种工具市面上较少 我这里还是使用 ibd2sql (夹带私货-_-)

目前不支持溢出页(默认置为NULL). 也不建议在mysql里面存储大数据.

数据类型基本上都支持, 不支持空间坐标字段(为啥? 因为要太复杂了, 一时半会解析不了…)

python3 main.py /tmp/ddcw_alltype_table.ibd --sql > /tmp/ddcw_alltype_table.sql

然后我们就可以把解析出来的sql导入数据库了. 当然也可以解析的时候直接通过管道写入数据库

mysql -h127.0.0.1 -P3314 -p123456 < /tmp/ddcw_alltype_table.sql

总结

虽然只剩一个ibd文件也能恢复数据, 但还是要备份. 毕竟这些工具不一定能用. (多数都有备份, 这些工具使用例子就少, 支持范围就小)

如果ibd2sql工具使用有啥问题, 请到github提相关issue, 附上ibd2sql版本和mysql版本, 最好能附上debug日志.

下载地址: https://github.com/ddcw/ibd2sql/archive/refs/tags/v1.1.tar.gz

单表恢复方案参考:

  1. pxb+binlog (binlog提取单表 看之前的文章)
  2. mysqldump+binlog
  3. 从库拷贝ibd文件
  4. innodb_force_recovery + mysqldump
  5. ibd2sql

附mysql数据类型
(懒得整理, 直接拿ibd2sql里面的代码来看吧, 将就)

innodb_read_data object:
read_varchar
read_char
read_varbinary
read_binary
read_bit
read_tinyint
read_smallint
read_mediumint
read_int
read_bigint
read_float
read_double
read_decimal #最离谱...
read_date
read_datetime
read_time
read_timestamp
read_year
read_enum
read_set

# json (可能存在溢出页)
read_json

# 大字段 (可能存在溢出页)
read_tinyblob
read_mediumblob
read_blob
read_longblob
read_tinytext
read_mediumtext
read_text
read_longtext

# 空间坐标(也NM离谱)
read_geometry #几何 (通用)
read_point #点
read_linestring #线
read_polygon #多边形

read_multipoint
read_multilinestring
read_multipolygon
read_geometrycollection #几何集合

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论