工具的名字叫做: undrop-for-innodb
代码地址: https://github.com/twindb/undrop-for-innodb
官方文档: https://recovery.twindb.com/
介绍工具的一篇ppt http://www.slideshare.net/akuzminsky/undrop-for-innodb
当MySQL 执行 Drop Table或者 Drop Database 的时候,InnoDB并没有删除数据,数据的Page还在磁盘上。
如果innodb_file_per_table 被设置成了 OFF, 则数据库在ibdata1上,如果 innodb_file_per_table 被设置成了 ON, 则数据在 .ibd文件中,MySQL已经删除了这个文件。
首先安装软件所需要的包: make gcc flex bison git
[root@centos~]# yum install make gcc flex bison git
下载代码
[root@centos~]# git clone https://github.com/twindb/undrop-for-innodb.git
Initializedempty Git repository in /root/undrop-for-innodb/.git/
remote:Counting objects: 221, done.
Receivingobjects: 100% (221/221), 1.10 MiB | 53 KiB/s, done.
remote: Total221 (delta 0), reused 0 (delta 0), pack-reused 221
Resolvingdeltas: 100% (53/53), done.
[root@centos~]# ls
anaconda-ks.cfg MySQL-5.6.27-1.el6.x86_64.rpm-bundle.tar MySQL-embedded-5.6.27-1.el6.x86_64.rpm MySQL-shared-compat-5.6.27-1.el6.x86_64.rpm
install.log MySQL-client-5.6.27-1.el6.x86_64.rpm MySQL-server-5.6.27-1.el6.x86_64.rpm MySQL-test-5.6.27-1.el6.x86_64.rpm
install.log.syslog MySQL-devel-5.6.27-1.el6.x86_64.rpm MySQL-shared-5.6.27-1.el6.x86_64.rpm undrop-for-innodb
3.编译代码
[root@centos~]# cd undrop-for-innodb/
[root@centosundrop-for-innodb]# ls
check_data.c dictionary include LICENSE print_data.c recover_dictionary.sh sql_parser.l stream_parser.c tables_dict.c
c_parser.c fetch_data.sh innochecksum.c Makefile README.md sakila sql_parser.y sys_parser.c test.sh
[root@centosundrop-for-innodb]# make
cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -c stream_parser.c
cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -pthread -lm stream_parser.o -o stream_parser
flex sql_parser.l
bison -o sql_parser.c sql_parser.y
sql_parser.y:conflicts: 6 shift/reduce
cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -c sql_parser.c
lex.yy.c:3084:警告:‘yyunput’定义后未使用
lex.yy.c:3125:警告:‘input’定义后未使用
cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -c c_parser.c
./include/ctype-latin1.c:359:警告:‘my_mb_wc_latin1’定义后未使用
./include/ctype-latin1.c:372:警告:‘my_wc_mb_latin1’定义后未使用
cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -c tables_dict.c
cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -c print_data.c
cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -c check_data.c
cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include sql_parser.oc_parser.o tables_dict.o print_data.o check_data.o -o c_parser -pthread -lm
cc -D_FILE_OFFSET_BITS=64-Wall -g -O3 -pipe -I./include -oinnochecksum_changer innochecksum.c
数据库的版本:MySQL-server-5.6.27
操作系统:Centos6.7 和 Windows 7
我们先来看下创建好的数据库,有多少个文件。
[root@centos mysql]#ls
auto.cnf centos.err centos.pid ibdata1 ib_logfile0 ib_logfile1 mysql mysql.sock performance_schema RPM_UPGRADE_HISTORY RPM_UPGRADE_MARKER-LAST test
确认下我们的数据库的 innodb_file_per_table参数
mysql> show variables like '%per_table%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_file_per_table | ON |
+-----------------------+-------+
1 row in set (0.00 sec)
说明:OFF代表mysql是共享表空间,也就是所有库的数据都存放在一个ibdate1文件中
ON代表,每个表的存储空间都是独立的。
接下来创建爱数据库 test1 并创建测试表 test1
mysql>create database test1;
Query OK, 1row affected (0.00 sec)
mysql> usetest1;
Databasechanged
mysql>create table test1(id int);
Query OK, 0rows affected (0.14 sec)
mysql>insert into test1 values('1');
Query OK, 1row affected (0.54 sec)
mysql>insert into test1 select * from test1; -----反复运行多次,直到有足够的数据量
Query OK,131072 rows affected (2.28 sec)
Records:131072 Duplicates: 0 Warnings: 0
mysql>commit;
Query OK, 0rows affected (0.00 sec)
我们来看下数据文件多了哪些。
[root@centosmysql]# ls
auto.cnf centos.err centos.pid ibdata1 ib_logfile0 ib_logfile1 mysql mysql.sock performance_schema RPM_UPGRADE_HISTORY RPM_UPGRADE_MARKER-LAST test test1
多了一个test1的目录。进入目录看下
[root@centosmysql]# cd test1
[root@centostest1]# ls
db.opt test1.frm test1.ibd
可以看到 test1.frm 和 test1.ibd 这2个文件。
ibd是MySQL数据文件、索引文件,无法直接读取。
frm是表结构文件,可以直接打开。
如果innodb_file_per_table 无论是ON还是OFF,都会有这2个文件,区别只是innodb_file_per_table为ON的时候,数据时放在 .idb中,如果为OFF则放在ibdata1中。
我们来看下数据文件的大小:
[root@centostest1]# du -sh *
4.0K db.opt
12K test1.frm
72M test1.ibd
[root@centosmysql]# du -sh *
4.0K auto.cnf
4.0K centos.err
4.0K centos.pid
76M ibdata1
49M ib_logfile0
48M ib_logfile1
1.7M mysql
0 mysql.sock
636K performance_schema
4.0K RPM_UPGRADE_HISTORY
4.0K RPM_UPGRADE_MARKER-LAST
4.0K test
8.0K test2
发现 test1.ibd和ibdata1 都增长的很厉害,不知道为什么,这个之后再研究。
接下来删除数据库test1
drop databasetest1.
注意这里 -f 后面的参数是 裸盘 的地址,如果你不知道可以用 df -h 查看.
-t 是这个磁盘的大小。
[root@centos~]# df -h /var/lib/mysql
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg_centos-lv_root
50G 4.1G 43G 9% /
[root@centosundrop-for-innodb]#./stream_parser -f /dev/mapper/vg_centos-lv_root -t 50g
Opening file:/dev/mapper/vg_centos-lv_root
Fileinformation:
ID of devicecontaining file: 5
inodenumber: 6454
protection: 60660 (block device)
number of hardlinks: 1
user ID ofowner: 0
group ID ofowner: 6
device ID (ifspecial file): 64768
blocksize forfilesystem I/O: 4096
number ofblocks allocated: 0
time of lastaccess: 1449240755 Fri Dec 4 22:52:35 2015
time of lastmodification: 1449240755 FriDec 4 22:52:35 2015
time of laststatus change: 1449240755 FriDec 4 22:52:35 2015
total size, inbytes: 0 (0.000exp(+0))
Size to process: 53687091200 (50.000 GiB)
Worker(0):1.03% done. 2015-12-05 00:04:40 ETA(in 00:14:38). Processing speed: 57.700MiB/sec
Worker(0):2.04% done. 2015-12-05 00:06:18 ETA(in 00:16:06). Processing speed: 51.902MiB/sec
Worker(0):3.06% done. 2015-12-05 00:01:27 ETA(in 00:11:08). Processing speed: 74.221MiB/sec
Worker(0):4.07% done. 2015-12-05 00:04:39 ETA(in 00:14:11). Processing speed: 57.672MiB/sec
…
Worker(0):98.51% done. 2015-12-04 23:54:19 ETA(in 00:00:05). Processing speed: 129.971MiB/sec
Worker(0):99.53% done. 2015-12-04 23:54:15 ETA(in 00:00:00). Processing speed: 520.000MiB/sec
All workersfinished in 263 sec
这里说明一下:
0000000000000001.page: 恢复出来的 SYS_TABLES 表
0000000000000003.page: 恢复出来的 SYS_INDEXES 表
创建存放恢复出来的文件的目录
[root@centosundrop-for-innodb]#mkdir -p dictionary dumps/default
[root@centosundrop-for-innodb]# ./c_parser -4Df./pages-vg_centos-lv_root/FIL_PAGE_INDEX/0000000000000001.page -t./dictionary/SYS_TABLES.sql -o./dumps/SYS_TABLES.dmp -l./dumps/SYS_TABLES.sql
恢复数据,因为我们是恢复删除掉的数据,所以一定要加参数D(注意是大写的D)。
然后查看生成出来的文件:
./dictionary/SYS_TABLES.sql 是创建表 SYS_TABLES的脚本。
./dumps/SYS_TABLES.dmp 是SYS_TABLES表里面的内容
./dumps/SYS_TABLES.sql 是恢复数据到SYS_TABLES的SQL语句。
这里我们查看 ./dumps/SYS_TABLES.dmp,可以看到我们删除掉的数据
因为我们在test1数据库中只有1个test1表。所以这里只能看到一个 test1。
可以看到 table_id 是 20。
接下来我们看下索引的信息
可以看到,索引的ID 是22
这里有个重点的地方,我们首先要有表结构的SQL语句。(如果没有的话,可以参考我另外的一篇文章来恢复表的结构)。
创建 test1/test1.sql , 输入如下内容
Create table test1
(
Id int
)
开始恢复数据:
./c_parser -6f pages-ibdata1/FIL_PAGE_INDEX/0000000000000022.page-t test1/test1.sql -o dumps/test1.dmmp -l dumps/test1.sql
启动数据库,创建数据库test1
mysql> create database test1;
Query OK, 1 row affected (0.03 sec)
mysql> use test1;
Database changed
运行 test1/test1.sql 创建表 test1, 然后运行 dumps/test1.sql 恢复数据
mysql> source dumps/test1.sql
Query OK, 0 rows affected (0.00 sec)
Query OK, 45794 rows affected (0.90 sec)
Records: 45794 Deleted: 0 Skipped: 0 Warnings:
检查数据,可以看到数据已经正常恢复了。
首先确认下 innodb_file_per_table的参数.
mysql> showvariables like 'inno%per%tab%';
+-----------------------+-------+
|Variable_name | Value |
+-----------------------+-------+
|innodb_file_per_table | ON |
+-----------------------+-------+
1 row in set(0.00 sec)
创建测试用的数据库表和数据
mysql>create database test6;
Query OK, 1row affected (0.00 sec)
mysql> usetest6
Databasechanged
mysql>create table a(id int);
Query OK, 0rows affected (0.08 sec)
mysql>create table b(id2 int);
Query OK, 0rows affected (0.06 sec)
mysql>insert into a values(1);
Query OK, 1row affected (0.07 sec)
mysql>insert into b values(1);
Query OK, 1row affected (0.04 sec)
mysql>commit;
Query OK, 0rows affected (0.00 sec)
查看下数据表的目录,可以看到只有 frm文件
[root@centostest6]# pwd
/var/lib/mysql/test6
[root@centostest6]# ls
a.frm b.frm db.opt
反复执行 Insert into aselect * from a; 直到有足够大的数据。
[root@centosmysql]# du -sh ibdata1
76M ibdata1
Ibdata1增长到了76M
删除数据库 test6
mysql> dropdatabase test6;
Query OK, 2rows affected (0.26 sec)
因为数据在ibdata1文件中,所以我们分析ibdata1文件
[root@centosundrop-for-innodb]# ./stream_parser -f /var/lib/mysql/ibdata1
Opening file:/var/lib/mysql/ibdata1
Fileinformation:
ID of devicecontaining file: 64768
inodenumber: 2621728
protection: 100660 (regular file)
number of hardlinks: 1
user ID ofowner: 498
group ID ofowner: 497
device ID (ifspecial file): 0
blocksize forfilesystem I/O: 4096
number ofblocks allocated: 155648
time of lastaccess: 1449385451 SunDec 6 15:04:11 2015
time of lastmodification: 1449385922 SunDec 6 15:12:02 2015
time of laststatus change: 1449385922 SunDec 6 15:12:02 2015
total size, inbytes: 79691776 (76.000 MiB)
Size toprocess: 79691776(76.000 MiB)
All workersfinished in 0 sec
剩下的步骤和之前的一样,首先获取到 我们删除掉的test6的数据库里面的表,从结果里面可以看到是 a 和b 。ID 分别是 24 和 25。
[root@centosundrop-for-innodb]# ./c_parser -4Df./pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page -t ./dictionary/SYS_TABLES.sql -o ./dumps/SYS_TABLES.dmp -l ./dumps/SYS_TABLES.sql
[root@centosundrop-for-innodb]# cat ./dumps/SYS_TABLES.dmp
-- Page id: 8,Format: REDUNDANT, Records list: Invalid, Expected records: (0 10)
000000000F6A 55000008010182 SYS_TABLES "test6/a" 24 1 1 0 64 "" 0
000000000F64 52000008060182 SYS_TABLES "test6/b" 25 1 1 0 64 "" 0
获取表中的索引信息
[root@centosundrop-for-innodb]# ./c_parser -4Df./pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t ./dictionary/SYS_INDEXES.sql
-- Page id:11, Format: REDUNDANT, Records list: Invalid, Expected records: (0 12)
000000000F6A 55000008010110 SYS_INDEXES 24 26 "GEN\_CLUST\_INDEX" 0 1 0 4294967295
000000000F64 52000008060110 SYS_INDEXES 25 27 "GEN\_CLUST\_INDEX" 0 1 0 4294967295
-- Page id:11, Found records: 2, Lost records: YES, Leaf page: YES
-- Page id:11, Format: REDUNDANT, Records list: Invalid, Expected records: (0 12)
000000000F6A 55000008010110 SYS_INDEXES 24 26 "GEN\_CLUST\_INDEX" 0 1 0 4294967295
000000000F64 52000008060110 SYS_INDEXES 25 27 "GEN\_CLUST\_INDEX" 0 1 0 4294967295
SETFOREIGN_KEY_CHECKS=0;
LOAD DATALOCAL INFILE '/root/undrop-for-innodb/dumps/default/SYS_INDEXES' REPLACE INTOTABLE `SYS_INDEXES` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"'LINES STARTING BY 'SYS_INDEXES\t' (`TABLE_ID`, `ID`, `NAME`, `N_FIELDS`,`TYPE`, `SPACE`, `PAGE_NO`);
-- Page id:11, Found records: 2, Lost records: YES, Leaf page: YES
可以看到索引ID分别是 26 和 27
创建建表的文件 test6/a.sql 和 test6/b.sql
开始恢复数据。
./c_parser -6fpages-ibdata1/FIL_PAGE_INDEX/0000000000000027.page -t test6/b.sql -odumps/b.dmmp -l dumps/b.sql
./c_parser -6fpages-ibdata1/FIL_PAGE_INDEX/0000000000000027.page -t test6/b.sql -odumps/b.dmmp -l dumps/b.sql
导入数据到数据库中
mysql>create database test6;
Query OK, 1row affected (0.00 sec)
mysql> usetest6;
Databasechanged
mysql>source test6/a.sql
Query OK, 0rows affected (0.07 sec)
mysql>source test6/b.sql
Query OK, 0rows affected (0.06 sec)
mysql>source dumps/a.sql
Query OK, 0rows affected (0.00 sec)
Query OK,1081922 rows affected (6.18 sec)
Records:1081922 Deleted: 0 Skipped: 0 Warnings: 0
mysql>source dumps/b.sql
Query OK, 0rows affected (0.00 sec)
Query OK, 2rows affected (0.07 sec)
Records:2 Deleted: 0 Skipped: 0 Warnings: 0
数据恢复成功
我考虑到了另外一种情况,如果是windows平台下删除了数据库,是否有办法通过这个软件来读取呢,我们可以试一下
查看下innodb_file_per_table的值:
mysql> show variables like 'inno%per%tab%';
+-----------------------+-------+
| Variable_name |Value |
+-----------------------+-------+
| innodb_file_per_table | ON |
+-----------------------+-------+
1 row in set (0.00 sec)
创建测试用的数据库 test_recover和表a1。
mysql> use test_recover;
Database changed
mysql> create table a1(a1 int,a2 int);
Query OK, 0 rows affected (0.40 sec)
mysql> insert into a1 values(1,2)
-> ;
Query OK, 1 row affected (0.11 sec)
mysql> insert into a1 values(3,4)
-> ;
Query OK, 1 row affected (0.08 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from a1;
+------+------+
| a1 | a2 |
+------+------+
| 1 | 2 |
| 3 | 4 |
+------+------+
2 rows in set (0.00 sec)
查看下我们的数据在哪个盘:
mysql> show variables like 'datadir';
+---------------+-----------------------------+
| Variable_name | Value |
+---------------+-----------------------------+
| datadir |D:\MyTool\xampp\mysql\data\ |
+---------------+-----------------------------+
1 row in set (0.00 sec)
删除数据库
首先安装 Samba。
yum install samba
因为我默认的administrator帐号没有密码,所以在windows上创建了一个用户 admin密码是 admin.
测试下帐号:
[root@centos~]# smbclient -L 10.0.0.4 -U admin
Enter admin'spassword:
Domain=[ACTION-PC]OS=[Windows 7 Ultimate 7601 Service Pack 1] Server=[Windows 7 Ultimate 6.1]
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk 远程管理
C$ Disk 默认共享
D$ Disk 默认共享
E$ Disk 默认共享
F$ Disk 默认共享
IPC$ IPC 远程 IPC
sessionrequest to 10.0.0.4 failed (Called name not present)
sessionrequest to 10 failed (Called name not present)
sessionrequest to *SMBSERVER failed (Called name not present)
NetBIOS overTCP disabled -- no workgroup available
创建 /d 目录,然后 将D盘挂载到本地的 /d 目录下
[root@centos~]# mount -t cifs -o username=admin,password=admin //10.0.0.4/d$ /d/
[root@centos~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg_centos-lv_root
50G 4.2G 43G 9% /
tmpfs 499M 0 499M 0% /dev/shm
/dev/sda1 477M 36M 416M 8% /boot
/dev/mapper/vg_centos-lv_home
47G 52M 45G 1% /home
//10.0.0.4/d$ 101G 89G 12G 89% /d
尝试去恢复数据:
[root@centosundrop-for-innodb]# ./stream_parser -f//10.0.0.4/d$ -t 101g
Opening file://10.0.0.4/d$
Fileinformation:
Errno = 2,Error = No such file or directory
All workersfinished in 0 sec
换个参数:
[root@centosundrop-for-innodb]# ./stream_parser -f/d/ -t 101g
Opening file:/d
Fileinformation:
ID of devicecontaining file: 28
inodenumber: 1407374883553285
protection: 40755 (directory)
number of hardlinks: 1
user ID ofowner: 0
group ID ofowner: 0
device ID (ifspecial file): 0
blocksize forfilesystem I/O: 16384
number ofblocks allocated: 80
time of lastaccess: 1449495079 MonDec 7 21:31:19 2015
time of lastmodification: 1449495079 MonDec 7 21:31:19 2015
time of laststatus change: 1449495079 MonDec 7 21:31:19 2015
total size, inbytes: 40960 (40.000 kiB)
Size toprocess: 108447924224(101.000 GiB)
Worker(0):Failed to read from disk: Is a directory
All workersfinished in 0 sec
最终都失败了。看来没有办法读取windows下的分区来恢复数据,不知道如果把物理磁盘挂载到Linux下会不会有效果。
分区是无法读取了,但是文件或许可以,让我们再次测试下。
查看下innodb_file_per_table的值:
mysql> showvariables like 'inno%per%tab%';
+-----------------------+-------+
|Variable_name | Value |
+-----------------------+-------+
| innodb_file_per_table| OFF |
+-----------------------+-------+
1 row in set(0.00 sec)
创建测试用的数据库 test_recover2和表 a2。
mysql>create database test_recover2;
Query OK, 1row affected (0.00 sec)
mysql> use test_recover2;
Databasechanged
mysql>create table a2(a1 int,a2 int);
Query OK, 0rows affected (0.40 sec)
mysql>insert into a2 values(1,2)
-> ;
Query OK, 1row affected (0.06 sec)
mysql>insert into a2 values(3,4)
-> ;
Query OK, 1row affected (0.04 sec)
mysql>insert into a2 values(5,6);
Query OK, 1row affected (0.06 sec)
mysql>commit;
Query OK, 0rows affected (0.00 sec)
mysql>select * from a2;
+------+------+
| a1 | a2 |
+------+------+
| 1 | 2 |
| 3 | 4 |
| 5 | 6 |
+------+------+
3 rows in set(0.00 sec)
查看下我们的数据在哪个盘:
mysql> showvariables like 'datadir';
+---------------+-----------------------------+
|Variable_name | Value |
+---------------+-----------------------------+
| datadir | D:\MyTool\xampp\mysql\data\|
+---------------+-----------------------------+
1 row in set(0.00 sec)
删除数据库
将 D:\MyTool\xampp\mysql\data目录下的 ibdata1 文件上传到Linux服务器的/tmp目录下
开始恢复数据
[root@centosundrop-for-innodb]# ./stream_parser -f/tmp/ibdata1
Opening file:/tmp/ibdata1
Fileinformation:
ID of devicecontaining file: 64768
inodenumber: 2753060
protection: 100644 (regular file)
number of hardlinks: 1
user ID ofowner: 0
group ID ofowner: 0
device ID (ifspecial file): 0
blocksize forfilesystem I/O: 4096
number ofblocks allocated: 155648
time of lastaccess: 1436277889 TueJul 7 22:04:49 2015
time of lastmodification: 1449498101 MonDec 7 22:21:41 2015
time of laststatus change: 1449498181 MonDec 7 22:23:01 2015
total size, inbytes: 79691776 (76.000 MiB)
Size toprocess: 79691776(76.000 MiB)
All workersfinished in 0 sec
然后解析文件,获取表的信息:
[root@centosundrop-for-innodb]# ./c_parser -4Df./pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page -t ./dictionary/SYS_TABLES.sql -o ./dumps/SYS_TABLES.dmp -l ./dumps/SYS_TABLES.sql
[root@centosundrop-for-innodb]# cat ./dumps/SYS_TABLES.dmp | grep recover
000000055C05 05000002181423 SYS_TABLES "test\_recover/a1" 1289 2 1 0 80 "" 1275
000000055C19 14000002042D29 SYS_TABLES "test\_recover2/a2" 1290 2 1 0 64 "" 0
000000055C05 05000002181423 SYS_TABLES "test\_recover/a1" 1289 2 1 0 80 "" 1275
000000055C19 14000002042D29 SYS_TABLES "test\_recover2/a2" 1290 2 1 0 64 "" 0
这里我们发现了上一次测试场景里面的 test_recover.a1表的信息。我们这里可以一起尝试恢复下
test_recover.a1 1289
test_recover2.a21290
分别获取这2个表的索引信息:
[root@centosundrop-for-innodb]# ./c_parser -4Df ./pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t ./dictionary/SYS_INDEXES.sql | grep 1289
00000000CCD1 58000001FA2FC1 SYS_INDEXES 841 1289 "PRIMARY" 1 3 827 3
SETFOREIGN_KEY_CHECKS=0;
[root@centosundrop-for-innodb]# ./c_parser -4Df./pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t ./dictionary/SYS_INDEXES.sql | grep 1290
000000055C19 14000002042C82 SYS_INDEXES 1290 1575 "GEN\_CLUST\_INDEX" 0 1 0 4294967295
00000000CCD8 5C0000025C1EBB SYS_INDEXES 842 1290 "PRIMARY" 2 3 828 3
000000055C19 14000002042C82 SYS_INDEXES 1290 1575 "GEN\_CLUST\_INDEX" 0 1 0 4294967295
SETFOREIGN_KEY_CHECKS=0;
LOAD DATALOCAL INFILE '/root/undrop-for-innodb/dumps/default/SYS_INDEXES' REPLACE INTOTABLE `SYS_INDEXES` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"'LINES STARTING BY 'SYS_INDEXES\t' (`TABLE_ID`, `ID`, `NAME`, `N_FIELDS`,`TYPE`, `SPACE`, `PAGE_NO`);
可以看到,只有1290找到了索引的ID是 1575 。test_recover.a1确实无法恢复了。
创建建表的文件 test_recover2/a2.sql
开始恢复数据。
[root@centosundrop-for-innodb]# ./c_parser -6fpages-ibdata1/FIL_PAGE_INDEX/0000000000001575.page -t test_recover2/a2.sql -odumps/a2.dmmp -l dumps/a2.sql
[root@centosundrop-for-innodb]# cat dumps/a2.dmmp
-- Page id:336, Format: COMPACT, Records list: Valid, Expected records: (3 3)
000000003500 000000055C11 8E000001410110 a2 1 2
000000003501 000000055C12 8F000002750110 a2 3 4
000000003502 000000055C17 92000002760110 a2 5 6
-- Page id:336, Found records: 3, Lost records: NO, Leaf page: YES
-- Page id:336, Format: COMPACT, Records list: Valid, Expected records: (3 3)
000000003500 000000055C11 8E000001410110 a2 1 2
000000003501 000000055C12 8F000002750110 a2 3 4
000000003502 000000055C17 92000002760110 a2 5 6
-- Page id:336, Found records: 3, Lost records: NO, Leaf page: YES
[root@centosundrop-for-innodb]#
可以看到数据可以恢复。
剩下的步骤就都一样了,创建表,然后加载数据。
Linux 平台: 都可以恢复。
Windows平台: 如果 innodb_file_per_table=OFF,则可以恢复,否则无法恢复。
恢复步骤:
用stream_parser 工具恢复数据。
如果 innodb_file_per_table=OFF, 所有数据在 ibdata1中,用下面的命令:
./stream_parser-f /var/lib/mysql/ibdata1
如果innodb_file_per_table=ON, 所有数据在数据目录下,用下面的命令:
./stream_parser -f /dev/mapper/vg_centos-lv_root -t 50g
需要用df查看到的逻辑卷的地址,并用-t 指定逻辑卷的大小。
运行完毕后,会在当前目录下生成一个pages-xxxxx 的目录。所有恢复出来的数据都在这个目录下。
用c_parser 来解析恢复出来的文件
0000000000000001.page 文件中是恢复出来的SYS_TABLES 的内容。
./c_parser -4Df ./pages-vg_centos-lv_root/FIL_PAGE_INDEX/0000000000000001.page -t ./dictionary/SYS_TABLES.sql -o ./dumps/SYS_TABLES.dmp -l ./dumps/SYS_TABLES.sql
查看SYS_TABLES.dmp ,找到需要恢复的表的ID。
page 文件中是恢复出来的 SYS_INDEXS的内容。
./c_parser -4Df./pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t ./dictionary/SYS_INDEXES.sql
查看结果,筛选出所需要恢复表所对应的索引ID
恢复数据
找到000000[索引ID].page 文件,解析,前提是我们必须要有该表的建表语句
./c_parser -6f pages-ibdata1/FIL_PAGE_INDEX/0000000000000027.page -ttest6/b.sql -o dumps/b.dump -l dumps/b.sql
恢复出来的数据在.dump 文件中,运行 test6/b.sql 创建表(如果没有建表语句的话,可以通过其他方式获取,在别的文章里面会提到),然后运行dumps/b.sql 加载数据。
[root@centos undrop-for-innodb]# ./c_parser -h
Error: Usage: ./c_parser -4|-5|-6 [-dDV] -f <InnoDBpage or dir> -t table.sql [-T N:M] [-b <external pages directory>]
Where
-f<InnoDB page(s)> -- InnoDB page or directory with pages(all pages shouldhave same index_id)
-t<table.sql> -- 将创建表的语句输出到table.sql 文件中
-o<file> -- Save dump in this file. Otherwise print to stdout
-l<file> -- Save SQL statements in this file. Otherwise print to stderr
-h -- Print this help
-d -- Process only those pages which potentiallycould have deleted records (default = NO)
-D -- 只恢复删除的数据(默认是No) (default = NO)
-U -- 只恢复没有删除的数据(默认是Yes) (default = YES)
-V -- Verbose mode (lots of debug information)
-4 -- innodb_datafile is in REDUNDANT format
-5 -- innodb_datafile is in COMPACT format
-6 -- innodb_datafile is in MySQL 5.6 format
-T -- retrieves only pages with index id = NM (N- high word, M - low word of id)
-b<dir> -- Directory where external pages can be found. Usually it ispages-XXX/FIL_PAGE_TYPE_BLOB/
-i<file> -- Read external pages at their offsets from <file>.
-p prefix -- Use prefix for a directoryname in LOAD DATA INFILE command
[root@centosundrop-for-innodb]# ./stream_parser -f /dev/mapper/vg_centos-lv_root -t 50g
Could notcreate directory pages-vg_centos-lv_root
mkdir(): File exists
如果看到这个错误,是因为已经存在 pages-vg_centos-lv_root这个目录了,只要删除这个目录就可以了。
[root@centos undrop-for-innodb]# ./c_parser -6fpages-ibdata1/FIL_PAGE_INDEX/0000000000000026.page -t test6/a.sql -odumps/a.dmmp -l dumps/a.sql
Line 2: syntax error at ''
1: create tablea(id int)
2:
Failed to parse table structure
这个错误是因为最后少了一个分号