mysql innodb 从 ibd 文件恢复表数据
最近内部的 mysql 数据库发生了一件奇怪的事,其中有一个表 users625 突然出现问题,
所有对它的操作都报错误 数据表不存在。
mysql> select count(*) from users625;
ERROR 1146 (42S02): Table 'km8.users625' doesn't exist
show tables 它还显示在列表里,在 mysql 数据目录中也可以找到对应的表文件,也没有
进行过删除操作,突然出现这样的错误非常奇怪。
内部运行环境:
| 名称 | 值 |
|---|---|
| OS | Debian Squeeze x64 |
| mysql 版本 | 5.1 |
| mysql 引擎 | innodb |
发生了什么
突然出现这种情况,第一反应必定是想办法将表中的用户数据找回,但是目前发生问题的情况与原因都不明晰,
不能轻举妄动。
查看 mysql 日志,在操作出错的时候,日志这样显示:
mysqld: 180926 11:10:53 InnoDB: cannot calculate statistics for table km8/users625
mysqld: InnoDB: because the .ibd file is missing. For help, please refer to
mysqld: InnoDB: http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html
mysqld: 180926 11:10:53 [ERROR] MySQL is trying to open a table handle but the .ibd file for
mysqld: table km8/users625 does not exist.
mysqld: Have you deleted the .ibd file from the database directory under
mysqld: the MySQL datadir, or have you used DISCARD TABLESPACE?
mysqld: See http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html
mysqld: how you can resolve the problem.
其中提到3个可追溯的点:
- ibd file
- DISCARD TABLESPACE
- http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html
了解这3点提到的内容,应该对判断情况有很好的帮助。
ibd file
日志中提问,是否丢失了 ibd 文件?先到 mysql 数据目录下查找,
.
├── ibdata1
├── .......
├── .......
└── km8
├── ............
├── ............
├── users625.frm
├── users625.ibd
├── ............
└── ............
users625 的 ibd 文件是存在的,与之一起的还有文件 users625.frm 。
根据官方文档对 frm 文件的描述,frm 文件是用来保存 table 表结构(即 table 的定义)的,无论使用什么存储引擎。
与之相对的,ibd 文件是用来存储表数据(即行数据)的,通常情况下,所有数据都会存储在系统的 ibd 文件,
但是当开启选项 innodb_file_per_table 的时候,每个表的数据会使用单独的 ibd 文件来存储。
当前的 mysql 就开启了这个选项,
[mysqld]
innodb_file_per_table=1
目前 frm 与 ibd 文件都存在,从中恢复数据便存在一些希望。
DISCARD TABLESPACE
日志中提到的 DISCARD TABLESPACE 其实是在猜测导致 ibd 文件丢失的原因,因为它会删除相应 table 的 ibd 文件(所谓 tablespace)。
> ALTER TABLE km8.users625 DISCARD TABLESPACE;
底层的 users625.ibd 文件就会被删除,丢失所有表数据。
根据目前情况来看, ibd 文件还存在,所以它不是导致错误的原因。
trouble shooting doc
日志中提到的参考链接,其中列举了多种情况,和当前问题相关的是一个子链接,
按照它提供的方法,尝试进行数据恢复。
数据恢复
官方文档提到的恢复数据的方法,思路很清晰:
- 启用相同版本的 mysql 实例(启用选项 innodb_file_per_table)
- 建立同样结构的数据表
- 替换 ibd 文件(保持文件权限一致)
- 导入 ibd 文件中的数据
- 使用 mysqldump,导出数据
- 将导出的数据导入原数据库
我按照这种方式尝试恢复数据,并不是那么顺利:
如何获得 table 表结构?
在第2步,需要建立同样结构的数据表,目前只有 frm 和 ibd 文件,怎么样得到 create table 命令?
根据底层数据存储的理解,table 表结构存储在 frm 文件中,而目前已经有相应的方法从中提取出 create table 命令,
这样就可以用于在新的 mysql 实例中建立 table 。
tablespace id 不对应?
在第4步,尝试导入数据的时候,
> ALTER TABLE km8.users625 IMPORT TABLESPACE;
ERROR 1030 (HY000): Got error -1 from storage engine
总是出现失败,同时在 mysql 新实例的日志中发现这样的错误:
mysqld: InnoDB: Error: tablespace id in file './km8/users625.ibd' is 18446744073709551615, but in the InnoDB
mysqld: InnoDB: data dictinary it is 1.
原来在内部,ibd 文件本身有一个 id,必须和 mysql innodb 内部的 table 元数据相对应,才可以进行导入。
根据错误信息搜索到一篇文章,其中提到两种办法:
- 重复建表,因为 mysql 内部的 tablespace id 是累计递增的,预先建立 (18446744073709551615 - 1)张表,再建立
users625 表,就可以对应 id,并进行导入。 - 修改 ibd 文件,因为 tablespace id 存储于 ibd 文件,找到它并将其修改为 1,使之与内部的 id 对应,就可以进行导入。
考虑第 1 种方法,要预先建立上亿张空表?!这根本不可能。
于是尝试第 2 种方法,研究 ibd 的文件格式,修改对应 id。
用二进制编辑器打开 users625.ibd 文件,

18:26:08 UTC - mysqld got signal 6. This could be because you hit a bug. It is also possible that this
binary or one of the libraries it was linked against is corrupt, improperly built or misconfigured.
This error can also be cuased by malfunctioning hardware.
不敢相信自己的眼睛,居然有错误 log 在二进制文件里?!ibd 的文件格式可没有这么说明过。
随便找一个邻居表正常的 ibd 文件作对比,

看来是出现了 bug ,崩溃的环境直接将数据文件给毁了,这也解释了为什么 tablespace id 会那么大,因为 log
覆盖了原本的 id 字段,使 mysql 解读出了一个好笑的数字。
暂时放弃
这种情况下,还没有办法将数据恢复回来,只能暂时将表删除,新建空表,保证上层应用程序可以运行。
将 ibd 文件备份下来,看后续还没有其它的办法将其恢复。
检测所有 table 状态
当前只发现一个出现问题的 table ,可能同时也有其它的 table 出现问题。对此需要做一个全面的检测,
检测有没有其它的表受到牵连。
$ mysqlcheck --all-databases
写在最后
数据库的备份是非常重要的!直接导入备份数据,是解决问题最保险最便捷的办法。
如果没有备份,遇到 bug 丢失数据,只能怪时运不济。
同时数据库也最好选择稳定的版本,降低出现 bug 的概率。
mysql innodb 从 ibd 文件恢复表数据的更多相关文章
- MySQL 利用frm文件和ibd文件恢复表结构和表数据
文章目录 frm文件和ibd文件简介 frm文件恢复表结构 ibd文件恢复表数据 通过脚本利用ibd文件恢复数据 通过shell脚本导出mysql所有库的所有表的表结构 frm文件和ibd文件简介 在 ...
- MySQL innodb引擎下根据.frm和.ibd文件恢复表结构和数据
记录通过.frm和.ibd文件恢复数据到本地 .frm文件:保存了每个表的元数据,包括表结构的定义等: .ibd文件:InnoDB引擎开启了独立表空间(my.ini中配置innodb_file_per ...
- mysql5.7根据.frm和.ibd文件恢复表结构和数据
一.恢复表结构 1.环境:Windows .mysql5.7:首先创建一个数据库,可以通过navicat来创建: 2.使用当前创建的数据库:use ww; 3.随意创建一张表,但是这张表的名字 ...
- mysql数据恢复:.frm和.ibd,恢复表结构和数据
mysql数据恢复:.frm和.ibd,恢复表结构和数据 一.恢复表结构 二.恢复表数据 相关内容原文地址: CSDN:她说巷尾的樱花开了:mysql根据.frm和.ibd文件恢复表结构和数据 博客园 ...
- 通过.frm表结构和.ibd文件恢复数据
整个恢复过程其实可以总结为下面几步: (1):恢复表结构 (2):复制出来创建表的sql语句 (3):恢复表数据(在恢复表数据的时候,首先需要解除当前创建的表与默认生成的.ibd文件间的关系,接着将要 ...
- mysql通过frm+ibd文件还原data
此方法只适合innodb_file_per_table = 1 当误删除ibdata 该怎么办? 如下步骤即可恢复: 1.准备工作 1)准备一台纯洁的mysql环境[从启动到现在没有 ...
- mysql 之 frm+ibd文件还原data
此方法只适合innodb_file_per_table = 1 当误删除ibdata 该怎么办? 如下步骤即可恢复: 1.准备工作 1)准备一台纯洁的mysql环境[从启动到现在 ...
- Oracle恢复表数据
Oracle恢复数据 在oracle 10g以及之后的版本,提供了回收站的机制,为了防止误操作将表数据清空而有回收机制. 换句话说,我们删除的表不会立马消失,而是进入回收站.下面我们可以查看回收站 查 ...
- mysql: 关于MySQL InnoDB锁行还是锁表?
baidu zone - 关于MYSQL Innodb 锁行还是锁表,深入讲解
随机推荐
- [SDOI2009]HH的项链(莫队)
嘟嘟嘟 这题原本莫队能过,自从某谷加强数据后好像就只能80了. 但这并不重要. (其实写这篇博客只是想记录一下莫队板子) 莫队,总而言之,离线,排序,暴力. #include<cstdio> ...
- weblogic之CVE-2018-3246 XXE分析
通过ftp通道将数据传出来.上传1.xml <!DOCTYPE xmlrootname [<!ENTITY % aaa SYSTEM "http://192.168.172.12 ...
- 理解JavaScript继承(二)
理解JavaScript继承(二) 5.寄生式继承 function object(o) { function F() {} F.prototype = o; return new F(); } fu ...
- java final使用
一:final 1:有时候 我们需要一些类,不要被继承.即阻止定义子类.不允许扩展的类叫做final类,如果一个类在定义的时候,用final定义的时候,表示这个类是final类.无法定义子类. 语法 ...
- locust
from locust import HttpLocust,TaskSet,task class UserVue(TaskSet): #tasks = {buy:1,consume:2} #设置权重 ...
- jQuery 学习笔记:jQuery 代码结构
jQuery 学习笔记:jQuery 代码结构 这是我学习 jQuery 过程中整理的笔记,这一部分主要包括 jQuery 的代码最外层的结构,写出来整理自己的学习成果,有错误欢迎指出. jQuery ...
- 用脚本js把结果转化为固定小数位的形式
function roundTo(base,precision) { var m=Math.pow(10,precision); var a=Math.round(base * m) / m; ret ...
- Linux下onvif客户端获取ipc摄像头 获取能力:GetCapabilities
GetCapabilities:获取能力,主要目的获取设备能力信息(获取媒体服务地址) 鉴权:但是在调用获取设备能力之前是需要鉴权的.ONVIF协议规定,部分接口需要鉴权,部分接口不需要鉴权,在调用需 ...
- Catalan&Stirling数
Catalan&Stirling数 Tags:数学 作业部落 评论地址 Catalan数 \(1,1,2,5,14,42,132,429,1430,4862,16796,58786...\) ...
- 用 eric6 与 PyQt5 实现python的极速GUI编程(系列03)---- Drawing(绘图)(3)-- 画线
[概览] 本文实现如下的程序:(在窗体中绘画出各种不同风格的线条) 主要步骤如下: 1.在eric6中新建项目,新建窗体 2.(自动打开)进入PyQt5 Desinger,编辑图形界面,保存 3.回到 ...