使用undrop-for-innodb恢复Innodb引擎下误删的数据

一、背景

作者在维护公司某小型系统数据库时,把本地测试环境和生产环境搞混了,使用drop database命令删除了生产系统中的某个库(再次提醒大家务必做好备份……,不要同时打开生产环境和本地环境的数据库)。执行了drop database命令了,立即发通知并停止Web系统,防止数据被覆盖。发愣几分钟后冷静下来开始思考解决方案。

二、分析

查看备份任务没有对该库进行备份;查看mysql配置,发现没有开始log_bin,不能使用log_bin恢复数据。使用undrop-for-innodb恢复Innodb引擎下误删的数据_第1张图片
使用SHOW VARIABLES LIKE '%datadir%'命令查看到数据文件存放在/var/lib/mysql下。
使用undrop-for-innodb恢复Innodb引擎下误删的数据_第2张图片
访问/var/lib/mysql发现数据目录下有一个ibdata1文件,说明没有开启innodb_file_per_table on功能。并立马对ibdata1文件进行了备份,后续恢复操作均在测试机上进行,以免再次对生产系统造成损坏。

使用undrop-for-innodb恢复Innodb引擎下误删的数据_第3张图片
在github上使用undrop innodb关键词发现undrop-for-innodb(https://github.com/twindb/undrop-for-innodb)工具,视乎看到了希望。
使用undrop-for-innodb恢复Innodb引擎下误删的数据_第4张图片

三、恢复操作

下载并编译undrop-for-innodb(需要make, gcc, flex ,bison)。安装完成后在目录下生成了stream_parser、c_parser等多个执行文件。将前面备份的ibdata1复制到~/mysql_restore/undrop-for-innodb目录下,作好恢复准备。整个恢复过程共分为4步。

cd ~/
mkdir mysql_restore
git clone https://github.com/twindb/undrop-for-innodb
cd undrop-for-innodb
make

1、扫描页文件

使用如下命令对ibdata1进行扫描,扫描完成后会在当前目录下生成pages-ibdata1目录,目录中分别有FIL_PAGE_INDEX、FIL_PAGE_TYPE_BLOB目录。我们重点关注FIL_PAGE_INDEX,该目录中存放了所有从ibdata1中扫描出来的页索引文件。

./stream_parser -f ibdata1

页索引文件名由一串数字.page组成,文件名中的数字是后续操作的关键。
使用undrop-for-innodb恢复Innodb引擎下误删的数据_第5张图片

2、恢复表结构

一般情况下表结构是存储在 frm 文件中,drop table 会删除 frm 文件,还好我们可以从 innodb 系统表里读取一些信息恢复表结构。innodb 系统表有SYS_COLUMNS 、SYS_FIELDS、 SYS_INDEXES 、SYS_TABLES
这几个表记录了所有库表的元数据,对于恢复工作非常重要。

根据MySQL的源码,这SYS_COLUMNS 、SYS_FIELDS、 SYS_INDEXES 、SYS_TABLES这4个表的数据分别位于页文件的最前面4个页中,使用下面的4条语句从这4个页中读出数据:

mkdir dumps
./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page -t dictionary/SYS_TABLES.sql > dumps/default/SYS_TABLES  2>dumps/default/SYS_TABLES.sql
./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000002.page -t dictionary/SYS_COLUMNS.sql > dumps/default/SYS_COLUMNS 2>dumps/default/SYS_COLUMNS.sql
./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t dictionary/SYS_INDEXES.sql > dumps/default/SYS_INDEXES 2>dumps/default/SYS_INDEXES.sql
./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/0000000000000004.page -t dictionary/SYS_FIELDS.sql > dumps/default/SYS_FIELDS 2>dumps/default/SYS_FIELDS.sql

页文件可能不是从1开始的,要根据自己的情况修改

dumps目录中的4个sql文件就是从ibdata1文件中恢复的所有表结构信息。使用如下命令将恢复出来的表结构恢复到mysql中的data_recovered数据库下(-p后放自己的root密码)。

# cat dumps/default/*.sql |  mysql -uroot -p*** eim3

命令执行完后即可在mysql中看到表已经恢复出来了,但是表中没有数据。将data_recovered中的每一个表的结构分别导出为sql文件并上传到undrop-for-innodb所在的目录中,比如使用sqlyog:
使用undrop-for-innodb恢复Innodb引擎下误删的数据_第6张图片

3、恢复表数据

首先找到想恢复的表对应的table_id和index_id,执行如下命令。

./c_parser -5Df pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page -t dictionary/SYS_TABLES.sql |grep 'eim3'

可以得到eim3库下每个表的table_id,例如下图的000000B31AB5,这一行第5列的158,就说明第4列的表名对应的table_id为158,记住这个数字。

使用如下命令可以获得每一个table_id对应的index_id:

./c_parser -5Df pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t dictionary/SYS_INDEXES.sql

如下图中的第4列就是table_id,第5列就是index_id。
使用undrop-for-innodb恢复Innodb引擎下误删的数据_第7张图片
将前面的table_id和index_id复制出来,在excel中使用table_id进行匹配,即可得出每个表的index_id。比如下图中eim3.users_bonus对应的table_id为158,158对应的index_id为438,则说明eim3.users_bonus这个表中的数据存放在0000000000000438.page这个页文件下。

在这里插入图片描述
我们使用如下命令即可将其中的数据恢复出来:

./c_parser -5Uf pages-ibdata1/FIL_PAGE_INDEX/0000000000000438.page -t obj_users_bonus.sql > dumps/default/users_bonus 2> dumps/default/users_bonus.sql

该命令会在dumps/default/下同时生成users_bonus 、users_bonus.sql两个文件,其中users_bonus 文件中存放了表中的数据,users_bonus.sql文件中存放了导入数据的命令。我们使用如下命令即可将数据恢复至表中。

 cat users_bonus.sql | mysql -u*** -proot eim3

或者使用Excel直接组合生成所有表的扫描指令和恢复指令,然后在主机中批量执行。
在这里插入图片描述
至此,所有数据全部恢复,再发通告上线系统。

你可能感兴趣的:(mysql)