为什么我们需要恢复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. java 全组合 与全排列

    一.全组合 public static void Combination( ) { /*基本思路:求全组合,则假设原有元素n个,则最终组合结果是2^n个.原因是: * 用位操作方法:假设元素原本有:a ...

  2. Angular4学习笔记(一)-环境搭建

    下载nodejs 下载地址 在命令行输入:npm -v 如果出现如下画面即安装成功 安装Angular的cli命令行工具 命令:sudo npm install -g @angular/cli 输入n ...

  3. 避免在构造函数中调用虚方法(Do not call overridable methods in constructors)

    CLR中说道,不要在构造函数中调用虚方法,原因是假如被实例化的类型重写了虚方法,就会执行派生类型对虚方法的实现.但在这个时候,尚未完成对继承层次结构中所有字段的初始化.所以,调用虚方法会导致不可预测的 ...

  4. TP5分页类

    <?php class Page { public $page; //当前页 public $total; //总记录数 public $listRows; //每页显示记录数 private ...

  5. 嵌入式Linux应用开发__求职要求

    A.熟悉嵌入式软件开发,有较好的C语言开发能力,熟悉Linux线程,信号量,同步,消息队列,网络编程,音频等:B.能够熟练使用GDB调试工具:C.熟悉linux脚本,对于Android编译环境有一定理 ...

  6. C#枚举类型和int类型相互转换

    C#枚举类型和int类型相互转换 C# 枚举(Enum) 枚举是一组命名整型常量.枚举类型是使用 enum 关键字声明的. C# 枚举是值数据类型.换句话说,枚举包含自己的值,且不能继承或传递继承. ...

  7. Android数据解析——JSON

    示例一: 有这样一个JSON需要解析,比如: {"thresholds": {"1e-3": 65.3,"1e-5": 76.5," ...

  8. 使用python删除一个文件或文件夹

    使用python删除一个文件或文件夹,需要使用os模块. import osos.remove(path) # path是文件的路径,如果这个路径是一个文件夹,则会抛出OSError的错误,这时需用用 ...

  9. day_5.21 py 高级编程

    1.禁止模块之间的循环调用 2.浅拷贝    只拷贝引用!!\ 3. 深拷贝  只要里面有引用就继续拷贝 4.copy,copy() 5. '''2018-5-21 11:39:52就业班 py高级 ...

  10. M - Sum

    XXX is puzzled with the question below: 1, 2, 3, ..., n (1<=n<=400000) are placed in a line. T ...