原创 更新于 时间( 2018-02-11 16:40:00) ( 1467) 次浏览 标签 : MySQL恢复
导读

MySQL 使用ibd文件恢复InnoDB表 ...

遇到的问题[Problem]

某天在写bug中,突然发现了另外一个bug,果断放下手中的bug 去解决另外的bug 。。。可能是办公室空调温度开太高了,热晕了,解决过程中,看着产品数据库,一列存储色号的列,值仅仅存储了 6-10个字节,类型却被设置成为 TEXT ,心想,这哪个煞笔设计的? 果断改为 Varchar 64 ,当下还不禁为自己的机智点了一个赞。

然后过了大概4-5天,悲剧了,下游客户端反应产品页面,最终查到是返回的数据很短。按图索骥,定位到原因是,mysql 存储的数据 ,只剩一点了,莫名其妙被砍断了。原因,当然就是上面从 TEXT 转换为 Varchar 带来的。

由于已经过了几天,也不能做全量的恢复,只能着手恢复 Mysql Innodb 的 单表了。哪种方法比较好呢?

正文 [Solution]

由于 Mysql 是部署在 阿里云 RDS上的,公司也比较屌丝,没有做双备实例,没有定时跑脚本备份(本来在Docker中还有的),摆在眼前的解决方式有两种,一种是:binlog 恢复,一种是 ibd 文件 和 frm 文件恢复。这里选择的是第二种,通过idb 恢复 表内容。

默认的备份方式是独立空间存储,所以,每个数据库的每个表都会对应一个ibd 文件,下载至本地,假设这张表名称为pc ,那么默认存储为 pc.ibd / pc.frm 。(idb存储的是内容,frm 存储的是结构)。

恢复

恢复1 用 ibdata1 和ibd frm 一起恢复

第一种方法,如果我们的服务器上有完整的 ibdata1 和ibd frm 三个文件的备份,直接将 product ibd 和 frmibdata1 放到对应的位置替换,然后重启mysql 即可

恢复2 用 ibd 恢复表

第二种方法,如果没有ibdata1文件备份,只有单表的idb文件,那么,可以在其他数据库重新创建一个数据库 (防止造成不必要的损失)。新建一张名为 pc 的数据表,注意 引擎是 innodb ,如果有结构的话,最好按照原来的结构直接生成。比如:

CREATE TABLE `productcolor` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `ProductNO` varchar(45) NOT NULL COMMENT '产品唯一编号',
  `RelatedID` varchar(45) DEFAULT NULL,
  `RGB` text NOT NULL COMMENT 'RGB值',
  `ColorNO` varchar(45) NOT NULL COMMENT '色号',
  `StyleID` int(11) DEFAULT NULL COMMENT 'Style唯一标示',
  `TypeID` int(11) DEFAULT NULL,
  `IsDeleted` tinyint(1) DEFAULT '0',
  `CreateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`ID`),
  KEY `idx_productno` (`ProductNO`)
) ENGINE=InnoDB AUTO_INCREMENT=19045 DEFAULT CHARSET=utf8mb4 COMMENT='产品颜色表';

这样就创建了一张和恢复的表结构一样的表,这样在你本地的 /usr/loacl/mysql/data/product/ 目录下就会有一个 pc.ibd 和 pc.frm (路径看你自己服务器来定)

通过vim 查看被删之前单表的ibd文件,通过 :%!xxd 查看 tablespaceid,将 tablespaceid 改成我们后来本地创建的数据库中表的 tablespaceid ,这里保存需要先 :%!xxd -r wq

复制修改了 tablespaceid 为新数据的 备份ibd文件 到新数据库中, 修改新数据库 中的 my.cnf 配置文件为恢复模式:

innodb_force_recovery = 6

然后重启数据库,即可恢复完成备份时刻的完整表数据,再通过mysqldump 导出导入到原数据库,实现单表ibd恢复操作。

吸取教训,以后一定要小心操作。。

Leon0204

打杂后端程序猿~

讨论区

发表评论
昵称:
评论:
验证