MySQL 利用frm文件和ibd文件恢复表数据

frm文件和ibd文件简介

在MySQL中,如果我们使用了默认的存储引擎innodb创建一张表,那么在文件夹下面就会出现表名.frm和表名.ibd两个文件,如果我们使用的是Myisam存储引擎,那么就会出现三个文件,这里我们给出例子:

[root@ /data/yeyz]#ll
total 580
-rw-rw---- 1 mysql mysql 8586 Apr 3 17:44 a.frm
-rw-rw---- 1 mysql mysql   0 Apr 3 17:44 a.MYD
-rw-rw---- 1 mysql mysql 1024 Apr 3 17:44 a.MYI
-rw-rw---- 1 mysql mysql 8586 Apr 3 17:44 b.frm
-rw-rw---- 1 mysql mysql 98304 Apr 3 17:45 b.ibd
-rw-rw---- 1 mysql mysql  61 Nov 23 09:54 db.opt
-rw-rw---- 1 mysql mysql 8556 Apr 29 21:37 tbl_test_2.frm
-rw-rw---- 1 mysql mysql 98304 Apr 29 21:37 tbl_test_2.ibd
-rw-rw---- 1 mysql mysql 8556 Apr 29 21:33 tbl_test.frm
-rw-rw---- 1 mysql mysql 98304 Apr 29 21:33 tbl_test.ibd
-rw-rw---- 1 mysql mysql 8614 Apr 29 21:40 test.frm
-rw-rw---- 1 mysql mysql 98304 Apr 29 21:43 test.ibd
-rw-rw---- 1 mysql mysql 8666 Apr 2 15:13 unstandard_ins.frm
-rw-rw---- 1 mysql mysql 98304 Apr 3 11:46 unstandard_ins.ibd
-rw-rw---- 1 mysql mysql 8586 Apr 3 17:44 yeyz.frm
-rw-rw---- 1 mysql mysql  28 Apr 3 17:44 yeyz.MYD
-rw-rw---- 1 mysql mysql 2048 Apr 3 17:44 yeyz.MYI

其中ibd文件是innodb的表数据文件,而frm文件是innodb的表结构文件,mysiam存储引擎的表中,frm是表结构,MYI文件是索引文件,而MYD文件是数据文件,从这里也可以看出,innodb存储引擎的索引和数据是在一起的,而Myisam存储引擎索引和数据是分开的。

需要注意的是,这个frm文件和ibd文件都是不能直接打开的。

考虑这样一种需求,数据库需要快速恢复一个表中的数据,而这个表所在的库的数据量非常大,恢复起来可能耗费的时间也比较长,那么全库恢复肯定不是最佳的选择。那这种情况下怎么办呢?我们可以使用frm文件盒ibd文件来对数据进行恢复。下面我们分析分析这个过程。

frm文件恢复表结构

当然,表结构需要使用frm文件来恢复。我们第一反应想到的是,可以把这两个文件直接拷贝到一个新的数据库实例中,然后直接启动实例,这样可以么?当然是不行的。侄儿要是能行,估计DBA都可以下岗了。哈哈,废话不多说,来看操作过程。

首先,我们创建一个新的实例专门用来恢复数据,如果你使用线上的某一台机器来执行恢复,那你必须承担数据库重启的风险以及DML阻塞的风险,所以最好的方法还是使用一台专门的实例来进行恢复。那么我们如何从frm文件中拿到我们想要的表结构呢?

我拿线上的一个记录慢日志的表举个例子,为了写着方便,表名称我写成了"aaa",这个表的结构是这样的:

mysql--root@localhost:test_recover 12:08:43>>show create table aaa\G
*************************** 1. row ***************************
    Table: aaa
Create Table: CREATE TABLE `aaa` (
 `maintain_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增列',
 `slowquery_filename` varchar(50) DEFAULT NULL COMMENT '慢日志文件名',
 `slowquery_path` varchar(150) DEFAULT NULL COMMENT '慢日志全路径',
 `slowquery_process` tinyint(20) unsigned NOT NULL DEFAULT '0' COMMENT '慢日志是否被解析',
 `slowquery_uploadtime` datetime DEFAULT CURRENT_TIMESTAMP,
 `slowquery_analyzetime` date DEFAULT NULL COMMENT '慢日志解析时间',
 `slowquery_starttime` date DEFAULT NULL,
 `slowquery_endtime` date DEFAULT NULL,
 `instance_ip` varchar(15) DEFAULT NULL COMMENT '慢日志IP地址',
 `instance_port` int(11) DEFAULT NULL COMMENT '慢日志端口号地址',
 PRIMARY KEY (`maintain_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set, 1 warning (0.01 sec)

要从frm文件中得到这样的一个表,我们要做的步骤如下:

1、在实例上创建一个同名的表aaa,由于我们不知道这个表的结构,我们可以给它设定只有一个字段id,也就是

create table aaa (id int);

我们知道,这个时候会在对应的data目录下生成新的aaa.frm和aaa.ibd文件,然后我们使用我们备份的aaa.frm来替代之前的aaa.frm,然后重启数据库。

是的,你没有看错,我们使用备份的表结构文件来替代它生成的表结构文件。

2.看看重启之后错误日志输出的结果吧,如下:

2019-03-22T03:17:28.652390Z 16
[Warning] InnoDB: Table test_recover/store_goods_price contains 1 user
defined columns in InnoDB, but 12 columns in MySQL. Please check
INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and http://dev.mysql.com/doc/refman/5.7/en/innodb-troubleshooting.html for how to resolve the issue.
2019-04-02T07:56:31.558461Z 41
[Warning] InnoDB: Table test_recover/dv_control contains 1 user defined
columns in InnoDB, but 14 columns in MySQL. Please check
 INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and http://dev.mysql.com/doc/refman/5.7/en/innodb-troubleshooting.html for how to resolve the issue.
2019-05-23T03:14:10.161122Z 92
[Warning] InnoDB: Table test_recover/aaa contains 1
user defined columns in InnoDB, but 10 columns in MySQL. Please check
INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and http://dev.mysql.com/doc/refman/5.7/en/innodb-troubleshooting.html for how to resolve the issue.

可以看到,10-12行的错误日志里面提示我们这个表aaa只包含1个字段,但是frm中包含10个字段,字段的数量不符。

这和我们预料的结果符合,因为我们在创建表aaa的时候,只给了他1个字段id,而我们要恢复的aaa表有10个字段,肯定是无法从frm中读取的。此时你可能很容易就能想到,如果我们把这个aaa表的字段调成10个,那么最终的结果是什么呢?

3.将aaa表的字段数量升级成10个,然后重新拷贝frm文件,修改配置文件中的参数innodb_force_recovery=6,我们看看最终的结果:

mysql--root:(none) 12:04:20>>use test_recover;
Database changed
mysql--root:test_recover 12:04:25>>create table aaa (id1 int,id2 int,id3 int,id4 int,id5 int,id6 int,id7 int,id8 int,id9 int,id10 int);
Query OK, 0 rows affected (0.03 sec)

mysql--root@localhost:test_recover 12:05:08>>show create table aaa\G
*************************** 1. row ***************************
    Table: aaa
Create Table: CREATE TABLE `aaa` (
 `id1` int(11) DEFAULT NULL,
 `id2` int(11) DEFAULT NULL,
 `id3` int(11) DEFAULT NULL,
 `id4` int(11) DEFAULT NULL,
 `id5` int(11) DEFAULT NULL,
 `id6` int(11) DEFAULT NULL,
 `id7` int(11) DEFAULT NULL,
 `id8` int(11) DEFAULT NULL,
 `id9` int(11) DEFAULT NULL,
 `id10` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

然后我们重启实例,再次查看表aaa,可以看到结果如下:

mysql--root:test_recover 12:08:43>>show create table aaa\G
*************************** 1. row ***************************
    Table: aaa
Create Table: CREATE TABLE `aaa` (
 `maintain_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增列',
 `slowquery_filename` varchar(50) DEFAULT NULL COMMENT '慢日志文件名',
 `slowquery_path` varchar(150) DEFAULT NULL COMMENT '慢日志全路径',
 `slowquery_process` tinyint(20) unsigned NOT NULL DEFAULT '0' COMMENT '慢日志是否被解析',
 `slowquery_uploadtime` datetime DEFAULT CURRENT_TIMESTAMP,
 `slowquery_analyzetime` date DEFAULT NULL COMMENT '慢日志解析时间',
 `slowquery_starttime` date DEFAULT NULL,
 `slowquery_endtime` date DEFAULT NULL,
 `instance_ip` varchar(15) DEFAULT NULL COMMENT '慢日志IP地址',
 `instance_port` int(11) DEFAULT NULL COMMENT '慢日志端口号地址',
 PRIMARY KEY (`maintain_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set, 1 warning (0.01 sec)

可以看到,我们想要的表结构已经从frm文件中恢复出来了,需要注意的是,这个过程中我们并没有使用ibd文件。

总结一下利用frm文件恢复表结构的步骤:

1、首先创建一个同名的表,然后启动实例

2、使用备份的frm文件替代生成的frm文件,重启实例

3、查看错误日志,从错误日志中获取到备份的frm文件中的字段数量m

4、重新创建同名表,保证字段数量为m,与备份表保持一致,然后重新拷贝备份的frm文件到对应目录

5、修改实例的配置文件中的参数innodb_force_recovery=6,然后重启数据库,就可以看到对应的表结构创建语句,我们把它保存下来,下一步恢复数据的时候要用。这一步相当重要

6、将参数innodb_force_recovery=6注释掉,重新使用默认的值,然后重启数据库,准备恢复表数据。

至此,表结构恢复完毕。

解释一下innodb_force_recovery参数,这个参数的最大值是6,在该等级下,仅支持一部分查询功能,DML都不支持,从名称就可以看出来,这是在一些强行恢复的场景下才会使用的参数,一般情况下这个参数可以不要,使用默认值就行。有兴趣更深了解的同学可以参考官方文档。

ibd文件恢复表数据

上一步执行完成之后,我们已经获取了对应的表结构,现在我们看看如何恢复表数据。

恢复表数据的方法比较简单,大体步骤如下:

1、利用我们上一步中获取的建表语句,重新创建一张表,然后执行:

flush  table aaa for export;

这个语法是将表里面的数据落盘,并获取该表的锁,为后面恢复做好准备。

2、然后我们使用如下语句:

alter table aaa discard tablespace;

这个语句会删除当前的ibd文件。

3、然后我们使用我们之前备份的ibd文件,将其拷贝到对应的实例目录下面

4、最后在将ibd文件重新加载进来,使用如下语句:

alter table aaa import tablespace;

重启数据库,这样,我们的数据就恢复成功了。

简单总结一下

整个恢复的流程算是介绍完了,其中比较巧妙的地方就是从frm文件中获取表结构信息,我们使用了两次拼凑表创建语句的方法,最终得到了待恢复的表的表结构,然后使用alter table discard tablespace和alter table import tablespace的方法来恢复表中的数据。整个过程看着比较复杂,其实完全可以按照步骤抽象出来一个脚本,这样在下次恢复的时候,只需要输入要恢复的表的名称,就可以快速的恢复表结构和数据,不失为一种应急的数据恢复预案。

以上就是MySQL 利用frm文件和ibd文件恢复表数据的详细内容,更多关于MySQL 恢复表数据的资料请关注我们其它相关文章!

(0)

相关推荐

  • MySQL单表ibd文件恢复方法详解

    前言: 随着innodb的普及,innobackup也成为了主流备份方式.物理备份对于新建slave,全库恢复的需求都能从容应对. 但当面临单表数据误删,或者单表误drop的情况,如果使用物理全备进行恢复呢? 下文将进行详细分析. 恢复过程中需要用到的工具,percona data recover tool : https://launchpad.net/percona-innodb-recovery-tool 情况一:误删部分数据,需要用最近一次备份覆盖 来自同一台机器的ibd恢复覆盖,且备份

  • InnoDB 类型MySql恢复表结构与数据

    前提:保存了需要恢复数据库的文件 .frm 和 .ibd 文件 条件:InnoDB 类型的 恢复表结构 1.新建一个数据库--新建一个表,表名和列数和需要恢复数据库相同 2.停止mysql服务器 service mysql stop , 3.在/usr/local/mysql/my.cnf 里面添加innodb_force_recovery = 6 4.将需要恢复的表.frm格式文件 覆盖/usr/local/mysql/data/数据库 下的.frm格式文件 5.启动mysql服务器 serv

  • MySQL使用全库备份数据恢复单表数据的方法

    前言 备份数据库时,采用了全库备份,但是因为某些原因需要回滚一个表的数据到备份数据库上,如果回滚整个库就比较费时间,因为可能这个表只有几十M,但是其它表可能有十几上百G,这时候就需要将需要恢复的表提取出来了 我们在实际工作中都遇到过这种情况,一个MySQL实例中可能有多个database.而我们备份时,通常采用完全备份,将所有database都备份到一个文件中. 但是,偶尔会遇到只恢复一个database或者一个表的情况.怎么解决呢? 现在有备份库fdcsqlmysql-2018_11_30-0

  • MYSQL使用.frm恢复数据表结构的实现方法

    我们都知道当我们建立数据表(innodb或myisam)时,会生成相应的文件(如:MYD,MYI,frm) 在这里,我们探讨下使用frm文件恢复 innodb和myisam类型表的结构,不过由于他们存储引擎的特性,所以恢复的方法也不一样,以下是详细的恢复过程. myisamchk "xxx.frm" myisamchk 可以试出来,库是不是 myisam 类型 1:恢复innodb类型数据表结构 我们先从test数据目录 copy一个innodb.frm文件到另外一个库(innodb)

  • 从MySQL全库备份中恢复某个库和某张表的方法

    在Mysqldump官方工具中,如何只恢复某个库呢? 全库备份 [root@HE1 ~]# mysqldump -uroot -p --single-transaction -A --master-data=2 >dump.sql 只还原erp库的内容 [root@HE1 ~]# mysql -uroot -pMANAGER erp --one-database <dump.sql 可以看出这里主要用到的参数是--one-database简写-o的参数,极大方便了我们的恢复灵活性. 那么如何从

  • 用mysqldump备份和恢复指定表的方法

    复制代码 代码如下: mysqldump -u user -p db tab1 tab2 > db.sql 恢复  复制代码 代码如下: mysql -u user -p db < db.sql 参考: 1.拷备文件          :   (保证数据库没有写操作(可以给表上锁定))直接拷贝文件不能移植到其它机器上,除非你正在拷贝的表使用MyISAM存储格式 2.mysqldump    :   mysqldump生成能够移植到其它机器的文本文件 例: 备份整个数据库     --> 

  • mysql 从 frm 文件恢复 table 表结构的3种方法【推荐】

    mysql 正常运行的时候,查看 table 的结构并不是困难的事. 但是有时 mysql 发生故障,这种方法便不再可行. 当遇到故障,通常使用新的 mysql 实例来恢复当前的数据. 建表是非常重要的步骤,我们必须有其它的方法来寻找 table 的结构. table 结构定义在哪里 通常关注的用户数据,底层都实际存储在 mysql 数据目录.  其它的元数据也不例外,比如 table 表结构的定义. mysql 数据目录文件结构是非常清晰的, •目录对应数据库 •frm 文件存储了 table

  • MySQL如何恢复单库或单表,以及可能遇到的坑

    前言: MySQL 逻辑备份工具最常用的就是 mysqldump 了,一般我们都是备份整个实例或部分业务库.不清楚你有没有做过恢复,恢复场景可能就比较多了,比如我想恢复某个库或某个表等.那么如何从全备中恢复单库或单表,这其中又有哪些隐藏的坑呢?这篇文章我们一起来看下. 1.如何恢复单库或单表 前面文章有介绍过 MySQL 的备份与恢复.可能我们每个数据库实例中都不止一个库,一般备份都是备份整个实例,但恢复需求又是多种多样的,比如说我想只恢复某个库或某张表,这个时候应该怎么操作呢? 如果你的实例数

  • MySQL 从全库备份中恢复指定的表和库示例

    MySQL 从备份数据库中恢复指定的表和库示例 在Mysqldump官方工具中,如何只恢复某个库呢? 全库备份 [root@HE1 ~]# mysqldump -uroot -p --single-transaction -A --master-data=2 >dump.sql 只还原erp库的内容 [root@HE1 ~]# mysql -uroot -pMANAGER erp --one-database <dump.sql 可以看出这里主要用到的参数是--one-database简写-o

  • MySQL单表恢复的步骤

    正休息的时候一个电话将我的睡意完全打散,"开发童鞋写update SQL的时候忘了加where条件了",相信每一个DBA同学听到这个消息的时候都有骂街的冲动吧.万幸只是单表写花了,而不是哪位大神在DB里面drop table玩.虽然已经很久没进行单表恢复了,但是还好步骤都印在脑海中,没有出问题的就恢复完了. 言归正传,记录一下单表恢复的步骤和关键点,提醒自己也提醒大家. 第一步: 找一台性能比较高的服务器作为还原机,从备份池中将最近的一次备份恢复到这台还原机上.当然这个前提是你有备份,

随机推荐