为什么我们需要恢复innodb的字典信息?当我们drop 一个表时,发现误操作,这时又没有备份,那么想恢复数据是非常困难的。所以我们想恢复被删除的表时,首先就需要恢复表结构,目前已经有了undrop-for-innodb这个工具,相比之前的工具percona-data-recovery-tool-for-innodb有了更大的进步,这两个工具都是同一个作者开发的。这个工具我以前也写了相关的博客--Percona Data Recovery Tool 单表恢复,现在undrop-for-innodb这个工具更加完美,少了很多限制。但是对于drop table以后表结构的恢复还是需要使用percona-data-recovery-tool-for-innodb。没有看见undrop-for-innodb可以恢复表结构,这也是比较遗憾的地方吧。

1.TwinDB恢复工具包编译安装

安装工具包依赖的软件

yum install gcc bison flex bzr -y

2.下载软件包并编译安装

[root@mysql-server- ~]# bzr branch lp:undrop-for-innodb
You have not informed bzr of your Launchpad ID, and you must do this to
write to Launchpad or access private data. See "bzr help launchpad-login".
Branched revision(s).
[root@mysql-server- ~]#
[root@mysql-server- ~]# cd undrop-for-innodb/
[root@mysql-server- undrop-for-innodb]# make
cc -g -O3 -I./include -c stream_parser.c
cc -g -O3 -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: shift/reduce
cc -g -O3 -I./include -c sql_parser.c
cc -g -O3 -I./include -c c_parser.c
cc -g -O3 -I./include -c tables_dict.c
cc -g -O3 -I./include -c print_data.c
cc -g -O3 -I./include -c check_data.c
cc -g -O3 -I./include sql_parser.o c_parser.o tables_dict.o print_data.o check_data.o -o c_parser -pthread -lm
cc -g -O3 -I./include -o innochecksum_changer innochecksum.c
[root@mysql-server- undrop-for-innodb]#

如果没有抛出错误,证明就ok了,会生成编译好的工具c_parser。

一. 解析 ibdata1

InnoDB的字典信息存储在ibdata1。因此,我们需要使用stream_parser工具对它进行解析并获得存储在字典中的记录页。该工具在make以后就自动生成了。

[root@mysql-server- undrop-for-innodb]# ./stream_parser -f /data/mysql/user_3306/data/ibdata1
Opening file: /data/mysql/user_3306/data/ibdata1
File information: ID of device containing file:
inode number:
protection: (regular file)
number of hard links:
user ID of owner:
group ID of owner:
device ID (if special file):
blocksize for filesystem I/O:
number of blocks allocated:
time of last access: Sun Aug ::
time of last modification: Sun Aug ::
time of last status change: Sun Aug ::
total size, in bytes: (26.000 MiB) Size to process: (26.000 MiB)
All workers finished in sec
[root@mysql-server- undrop-for-innodb]#

stream_parser这个工具发现在ibdata1中,找到了存储页面类型(FIL_PAGE_INDEX或FIL_PAGE_TYPE_BLOB)由index_id的整理InnoDB的页面。

[root@mysql-server- pages-ibdata1]# pwd
/root/undrop-for-innodb/pages-ibdata1
[root@mysql-server- pages-ibdata1]# ll
total
drwxr-xr-x root root Aug : FIL_PAGE_INDEX
drwxr-xr-x root root Aug : FIL_PAGE_TYPE_BLOB
[root@mysql-server- pages-ibdata1]#

SYS_TABLES

SYS_TABLES本身是一个表,该表用于规范innodb各种表定义和保存innodb中各种表的基本信息,结合SYS_COLUMNS,SYS_INDEXES和SYS_FOREIGN系统表定义了特定某个表的所有信息。

[root@mysql-server- undrop-for-innodb]# ll pages-ibdata1/FIL_PAGE_INDEX/.page
-rw-r--r-- root root Aug : pages-ibdata1/FIL_PAGE_INDEX/.page

SYS_INDEXES

SYS_INDEXES用于保存innodb中每个表定义的每个索引对象。

[root@mysql-server- undrop-for-innodb]# ll pages-ibdata1/FIL_PAGE_INDEX/.page
-rw-r--r-- root root Aug : pages-ibdata1/FIL_PAGE_INDEX/.page

SYS_COLUMNS

SYS_COLUMNS用于保存innodb引擎每个表定义的列,与SYS_TABLES相似。

[root@mysql-server- undrop-for-innodb]# ll pages-ibdata1/FIL_PAGE_INDEX/.page
-rw-r--r-- root root Aug : pages-ibdata1/FIL_PAGE_INDEX/.page

SYS_FIELDS

SYS_FIELDS用于保存innodb中每个索引的每个列对象。

[root@mysql-server- undrop-for-innodb]# ll pages-ibdata1/FIL_PAGE_INDEX/.page
-rw-r--r-- root root Aug : pages-ibdata1/FIL_PAGE_INDEX/.page

从SYS_TABLES和SYS_INDEXES导出记录 

获取记录了需要使用c_parser工具。但首先我们要创建转存的数据目录

[root@mysql-server- undrop-for-innodb]# mkdir -p dumps/default
[root@mysql-server- undrop-for-innodb]#

InnoDB的字典总是在冗余格式,因此选择-4是必需的:

[root@mysql-server- undrop-for-innodb]# ./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/.page -t dictionary/SYS_TABLES.sql > dumps/default/SYS_TABLES > dumps/default/SYS_TABLES.sql
[root@mysql-server- undrop-for-innodb]#

现在找到我们关心的数据库,我之前有导入MySQL官方的示例数据库,sakila

[root@mysql-server- undrop-for-innodb]# grep sakila dumps/default/SYS_TABLES
SYS_TABLES "sakila/actor" ""
SYS_TABLES "sakila/address" ""
SYS_TABLES "sakila/category" ""
960000013A0110 SYS_TABLES "sakila/city" ""
970000013D0110 SYS_TABLES "sakila/country" ""
SYS_TABLES "sakila/customer" ""
9A000001460110 SYS_TABLES "sakila/film" ""
00000000031B 9C0000014C0110 SYS_TABLES "sakila/film\_actor" ""
00000000031D 9E000001500110 SYS_TABLES "sakila/film\_category" ""
00000000031F A0000001540110 SYS_TABLES "sakila/inventory" ""
A2000001590110 SYS_TABLES "sakila/language" ""
A30000015B0110 SYS_TABLES "sakila/payment" ""
A6000001620110 SYS_TABLES "sakila/rental" ""
A90000016A0110 SYS_TABLES "sakila/staff" ""
00000000032A AB0000016F0110 SYS_TABLES "sakila/store" ""
[root@mysql-server- undrop-for-innodb]#

可见该库下的所有表都看见了(用过sakila示例库的同学都知道^_^)。

dumps/default/SYS_TABLES使使用LOAD DATA INFILE命令生成的。具体的命令c_parsers打印到标准错误输出。把改SQL保存在了dumps/default/SYS_TABLES.sql

[root@mysql-server- undrop-for-innodb]# cat dumps/default/SYS_TABLES.sql
SET FOREIGN_KEY_CHECKS=;
LOAD DATA LOCAL INFILE '/root/undrop-for-innodb/dumps/default/SYS_TABLES' REPLACE INTO TABLE `SYS_TABLES` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"' LINES STARTING BY 'SYS_TABLES\t' (`NAME`, `ID`, `N_COLS`, `TYPE`, `MIX_ID`, `MIX_LEN`, `CLUSTER_NAME`, `SPACE`);

用同样的方法导出SYS_INDEXES:

[root@mysql-server- undrop-for-innodb]# ./c_parser -4f pages-ibdata1/FIL_PAGE_INDEX/.page -t dictionary/SYS_INDEXES.sql > dumps/default/SYS_INDEXES > dumps/default/SYS_INDEXES.sql
[root@mysql-server- undrop-for-innodb]#

查看一下结果,确保没有异常。

[root@mysql-server- undrop-for-innodb]# head - dumps/default/SYS_INDEXES
-- Page id: , Format: REDUNDANT, Records list: Valid, Expected records: ( )
810000012D0177 SYS_INDEXES "ID\_IND"
810000012D01A5 SYS_INDEXES "FOR\_IND"
810000012D01D3 SYS_INDEXES "REF\_IND"
810000012D026D SYS_INDEXES "ID\_IND"
[root@mysql-server- undrop-for-innodb]# head - dumps/default/SYS_INDEXES.sql
SET FOREIGN_KEY_CHECKS=;
LOAD DATA LOCAL INFILE '/root/undrop-for-innodb/dumps/default/SYS_INDEXES' REPLACE INTO TABLE `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`);
[root@mysql-server- undrop-for-innodb]#

现在我们可以使用字典了,如果表在数据库中,那么会更加方便。
加载字典表到MySQL

通过grep可以从SYS_TABLES和SYS_INDEXES的主要用途是得到为了表名index_id。如果SYS_TABLES和SYS_INDEXES在MySQL中,那么操作将变得更简单。

root@localhost : (none) 18:10:31> create database yayun;
Query OK, 1 row affected (0.00 sec) root@localhost : (none) 18:10:42>

上面创建的库主要用来导入两张表而已。

[root@mysql-server- undrop-for-innodb]# mysql -uroot -p123456 -S /data/mysql/user_3306/mysql.sock yayun < dictionary/SYS_TABLES.sql
[root@mysql-server- undrop-for-innodb]# mysql -uroot -p123456 -S /data/mysql/user_3306/mysql.sock yayun < dictionary/SYS_INDEXES.sql
[root@mysql-server- undrop-for-innodb]#

继续导入数据

[root@mysql-server- undrop-for-innodb]# mysql -uroot -p123456 -S /data/mysql/user_3306/mysql.sock yayun < dumps/default/SYS_TABLES.sql
[root@mysql-server- undrop-for-innodb]# mysql -uroot -p123456 -S /data/mysql/user_3306/mysql.sock yayun < dumps/default/SYS_INDEXES.sql
[root@mysql-server- undrop-for-innodb]#

现在我们的InnoDB字典信息已经存在在MySQL中,我们可以像普通的表进行查询

root@localhost : (none) 20:56:44> use yayun
Database changed
root@localhost : yayun 20:56:48> SELECT * FROM SYS_TABLES WHERE NAME = 'sakila/actor';
+--------------+----+--------+------+--------+---------+--------------+-------+
| NAME | ID | N_COLS | TYPE | MIX_ID | MIX_LEN | CLUSTER_NAME | SPACE |
+--------------+----+--------+------+--------+---------+--------------+-------+
| sakila/actor | 13 | 4 | 1 | 0 | 0 | | 0 |
+--------------+----+--------+------+--------+---------+--------------+-------+
1 row in set (0.08 sec) root@localhost : yayun 20:56:51> SELECT * FROM SYS_INDEXES WHERE TABLE_ID = 13;
+----------+----+---------------------+----------+------+-------+---------+
| TABLE_ID | ID | NAME | N_FIELDS | TYPE | SPACE | PAGE_NO |
+----------+----+---------------------+----------+------+-------+---------+
| 13 | 15 | PRIMARY | 1 | 3 | 0 | 307 |
| 13 | 16 | idx_actor_last_name | 1 | 0 | 0 | 308 |
+----------+----+---------------------+----------+------+-------+---------+
2 rows in set (0.05 sec) root@localhost : yayun 20:58:14>

通过上述的查询,我们可以看到sakila.actor表有两个索引,PRIMARY和idx_actor_last_name,分别对应15,16,。如果我们不小心误操作,drop table actor,那么恢复数据就需要知道相应的id。后续文章将介绍drop table后如何恢复数据。

参考资料

https://twindb.com/how-to-recover-innodb-dictionary/

https://twindb.com/innodb-dictionary/

Recover InnoDB dictionary的更多相关文章

  1. DROP TABLE 恢复【一】

    当DROP TABLE指令敲下的时候,你很爽,你有考虑过后果么?如果该表真的没用,你DROP到无所谓,如果还有用的,这时你肯定吓惨了吧,如果你有备份,那么恭喜你,逃过一劫,如果没有备份呢?这时就该绝望 ...

  2. MySQL Flashback 工具介绍

    MySQL Flashback 工具介绍 DML Flashback 独立工具,通过伪装成slave拉取binlog来进行处理 MyFlash 「大众点点评」 binlog2sql 「大众点评(上海) ...

  3. ORCLE INNODB 博客与 innodb_lru_scan_depth

    https://blogs.oracle.com/mysqlinnodb/ http://mysqllover.com/?p=485 •MySQL. MySQL 5.6.10 http://www.m ...

  4. 记一次揪心的MySQL数据恢复过程

    https://blog.csdn.net/poxiaonie/article/details/78304699 === 先说下背景,公司其中一个项目所有服务都部署在客户的机房内,机房较小,没有UPS ...

  5. ha_innobase::open

    http://mysql.taobao.org/monthly/2015/08/07/ /******************************************************* ...

  6. Innodb 表修复(转)

    摘要:      突然收到MySQL报警,从库的数据库挂了,一直在不停的重启,打开错误日志,发现有张表坏了.innodb表损坏不能通过repair table 等修复myisam的命令操作.现在记录下 ...

  7. Recovering InnoDB table from an .ibd file.

    Recovering an InnoDB table from only an .ibd file. Sometime you may need to recover a table when all ...

  8. MySQL 5.6 Reference Manual-14.6 InnoDB Table Management

    14.6 InnoDB Table Management 14.6.1 Creating InnoDB Tables 14.6.2 Moving or Copying InnoDB Tables to ...

  9. MySQL 5.6 Reference Manual-14.5 InnoDB Tablespace Management

    14.5 InnoDB Tablespace Management   14.5.1 Resizing the InnoDB System Tablespace 14.5.2 Changing the ...

随机推荐

  1. Angular4学习笔记(十)- 组件间通信

    分类 父子组件通信 非父子组件通信 实现 父子 父子组件通信一般使用@Input和@Output即可实现,参考Angular4学习笔记(六)- Input和Output 通过Subject 代码如下: ...

  2. 磨刀不误砍柴工——统一日志系统 Log4Net/ExceptionLess

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫必须注明原文地址:www.cnblogs.com/tdws . 一.   写在前面 本文Log4Net介绍了基础的方式,大数据量生产环境不能使用,中等 ...

  3. STL中的map、unordered_map、hash_map

    转自https://blog.csdn.net/liumou111/article/details/49252645 在之前使用STL时,经常混淆的几个数据结构,特别是做Leetcode的题目时,对于 ...

  4. windows上测试磁盘io性能

    一.问题由来 前两天搭建一套演示环境,同样的java war包,放在我们这边服务器好好的,放在那边就运行缓慢. 后来把日志改成异步之后就好了. 后边找了个程序测了下io性能,竟然差了7,8倍. 二.软 ...

  5. 图表统计FusionCharts

    工作中用的图形统计,用的FusionCharts,发现Chenssy总结了很详细了,特此记录一下.tks Chenssy. tks: http://www.cnblogs.com/chenssy/ar ...

  6. 6 CLR实例构造器

    引用类型构造器 如果我们没有定义实例构造器,那么编译器会为我们默认产生一个无参构造器. 实例对象初始化过程 为实例分配内存: 初始化附加成员,包括方法表指针和SyncBlockIndex变量(我们已经 ...

  7. SQL中的Continue和Break

    x 在Sql Server中,sql语句包含While循环的时候,肯定都或多或少的用到Continue和Break... 下面撸了一个小Demo , Begin ),@Index) Begin Pri ...

  8. 省一行是一行:在if语句中使用C# 7.0的模式匹配

    C# 7.0的模式匹配(Pattern Mathing)不仅可以节省代码,而且可以让代码更流畅(Fluent),今天又在实际开发中体会了一下. 不用模式匹配的代码,需要先获取返回值,然后用if进行判断 ...

  9. opencv学习笔记——cv::CommandLineParser函数详解

    命令行解析类CommandLineParser 该类的作用主要用于命令行的解析,也就是分解命令行的作用.以前版本没这个类时,如果要运行带参数的.exe,必须在命令行中输入文件路径以及各种参数,并且输入 ...

  10. 使用hive分析nginx访问日志方法

    以下案例是使用hive分析nginx的访问日志案例,其中字段分隔通过正则表达式匹配,具体步骤如下: 日志格式: 192.168.5.139 - - [08/Jun/2017:17:09:12 +080 ...