当DROP TABLE指令敲下的时候,你很爽,你有考虑过后果么?如果该表真的没用,你DROP到无所谓,如果还有用的,这时你肯定吓惨了吧,如果你有备份,那么恭喜你,逃过一劫,如果没有备份呢?这时就该绝望了?NO! 如果你的表是innodb表,那么还有希望挽救,如果是myisam表,那么真的没救了。前面文章介绍了 Recover InnoDB dictionary,这是恢复数据的前提。恢复innodb字典信息使用的是TwinDB recovery toolkit,我们恢复数据也是使用该工具。下面的案例是基于innodb_file_per_table=OFF的前提下,即使用共享表空间,所有的信息都保存在ibdata1中。使用独立表空间DROP TABLE后数据恢复将在后面的文章介绍。

错误的操作--删除表

用到的示例数据库还是sakila,关于下载地址前面的文章有地址。将模拟把sakila库中的actor表删除后进行恢复。

root@localhost : sakila 21:34:11>  SELECT * FROM actor LIMIT 10;
+----------+------------+--------------+---------------------+
| actor_id | first_name | last_name | last_update |
+----------+------------+--------------+---------------------+
| 1 | PENELOPE | GUINESS | 2006-02-15 04:34:33 |
| 2 | NICK | WAHLBERG | 2006-02-15 04:34:33 |
| 3 | ED | CHASE | 2006-02-15 04:34:33 |
| 4 | JENNIFER | DAVIS | 2006-02-15 04:34:33 |
| 5 | JOHNNY | LOLLOBRIGIDA | 2006-02-15 04:34:33 |
| 6 | BETTE | NICHOLSON | 2006-02-15 04:34:33 |
| 7 | GRACE | MOSTEL | 2006-02-15 04:34:33 |
| 8 | MATTHEW | JOHANSSON | 2006-02-15 04:34:33 |
| 9 | JOE | SWANK | 2006-02-15 04:34:33 |
| 10 | CHRISTIAN | GABLE | 2006-02-15 04:34:33 |
+----------+------------+--------------+---------------------+
10 rows in set (0.01 sec) root@localhost : sakila 21:34:25>
root@localhost : sakila 21:34:25> CHECKSUM TABLE actor;
+--------------+------------+
| Table | Checksum |
+--------------+------------+
| sakila.actor | 2472295518 |
+--------------+------------+
1 row in set (0.07 sec) root@localhost : sakila 21:35:30> SET foreign_key_checks=OFF;
Query OK, 0 rows affected (0.00 sec) root@localhost : sakila 21:35:46> DROP TABLE actor;
Query OK, 0 rows affected (0.07 sec) root@localhost : sakila 21:35:57>

从ibdata1恢复数据

现在actor表已经删除,但表中的信息仍然存与ibdata1中。该数据保持不变,直到InnoDB的重用空闲的页。我们需要尽快停止mysqld进程。
对于恢复,我们将使用TwinDB恢复工具包。看看我前面的文章Recover InnoDB dictionary

解析innodb表空间(ibdata1)

InnoDB将所有数据存储在B +树索引。 一个表有只有一个聚集索引,所有字段存储在这里。 如果表有辅助索引,由index_id标识每个索引。

如果我们要恢复一个表,我们必须找到属于特定index_id的所有页面。

stream_parser读取InnoDB表和排序按类型和每个index_id的InnoDB的页面。

[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将把数据从page保存到pages-ibdata1

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

现在InnoDB表空间的每个index_id被保存在一个单独的文件。我们可以用c_parser工具从page提取记录。但是,我们需要知道哪个index_id对应表Sakila/actor。这些信息,我们可以从字典中获取:SYS_TABLES和SYS_INDEXES。

SYS_TABLES始终存储在文件index_id为1的page,ibdata1/FIL_PAGE_INDEX/0000000000000001.page 这让我们找到Sakila/actor表的标识符。如果MySQL有足够的时间来刷新到磁盘的变化再加入D选项,意思是“寻找被删除的记录“,innodb字典信息永远是冗余格式,所以我们需要指定选项-4。

[root@mysql-server- undrop-for-innodb]# ./c_parser -4Df pages-ibdata1/FIL_PAGE_INDEX/.page -t dictionary/SYS_TABLES.sql | grep sakila/actor
45000002B902C8 SYS_TABLES "sakila/actor" ""
45000002B902C8 SYS_TABLES "sakila/actor" ""
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`);
[root@mysql-server- undrop-for-innodb]#

注意表名之后的数13。这是表标识符。这和前面的文章不谋而合,Recover InnoDB dictionary

接下来的事情,需要做的是找到actor表的的主键ID。为此,我们将从SYS_INDEXES文件0000000000000003.page获取记录(该表将包含有关index_id和表标识符信息)。 SYS_INDEXES的结构需要通过-t选项解析。

[root@mysql-server- undrop-for-innodb]# ./c_parser -4Df pages-ibdata1/FIL_PAGE_INDEX/.page -t dictionary/SYS_INDEXES.sql | grep
45000002B90145 SYS_INDEXES "PRIMARY"
45000002B901B7 SYS_INDEXES "idx\_actor\_last\_name"
45000002B90145 SYS_INDEXES "PRIMARY"
45000002B901B7 SYS_INDEXES "idx\_actor\_last\_name"
45000002B90145 SYS_INDEXES "PRIMARY"
45000002B901B7 SYS_INDEXES "idx\_actor\_last\_name"
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]#

我们可以从输出看到,PRIMARY index_id标示符是15。因此,我们的数据将从0000000000000015.page寻找。

[root@mysql-server- undrop-for-innodb]# ./c_parser -6f pages-ibdata1/FIL_PAGE_INDEX/.page -t sakila/actor.sql |  head -
-- Page id: , Format: COMPACT, Records list: Valid, Expected records: ( )
00000000032C AD000001750110 actor "PENELOPE" "GUINESS" "2006-02-15 04:34:33"
00000000032C AD00000175011A actor "NICK" "WAHLBERG" "2006-02-15 04:34:33"
00000000032C AD000001750124 actor "ED" "CHASE" "2006-02-15 04:34:33"
00000000032C AD00000175012E actor "JENNIFER" "DAVIS" "2006-02-15 04:34:33"
00000000032C AD000001750138 actor "JOHNNY" "LOLLOBRIGIDA" "2006-02-15 04:34:33"
00000000032C AD000001750142 actor "BETTE" "NICHOLSON" "2006-02-15 04:34:33"
00000000032C AD00000175014C actor "GRACE" "MOSTEL" "2006-02-15 04:34:33"
00000000032C AD000001750156 actor "MATTHEW" "JOHANSSON" "2006-02-15 04:34:33"
00000000032C AD000001750160 actor "JOE" "SWANK" "2006-02-15 04:34:33"
[root@mysql-server- undrop-for-innodb]#

看见上面的输出,是不是觉得希望来了?哈哈
上面的结果正是我们想要的,我们现在把数据存贮在文件中,然后倒入,创建dump/default目录存储数据。

[root@mysql-server- undrop-for-innodb]#  mkdir -p dumps/default
[root@mysql-server- undrop-for-innodb]#
[root@mysql-server- undrop-for-innodb]# ./c_parser -6f pages-ibdata1/FIL_PAGE_INDEX/.page -t sakila/actor.sql > dumps/default/actor > dumps/default/actor_load.sql
[root@mysql-server- undrop-for-innodb]#

我们看看一个文件,其实是命令加载表而已

[root@mysql-server- undrop-for-innodb]# cat dumps/default/actor_load.sql
SET FOREIGN_KEY_CHECKS=;
LOAD DATA LOCAL INFILE '/root/undrop-for-innodb/dumps/default/actor' REPLACE INTO TABLE `actor` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"' LINES STARTING BY 'actor\t' (`actor_id`, `first_name`, `last_name`, `last_update`);
[root@mysql-server- undrop-for-innodb]#

将数据load回数据库中
现在将数据恢复到数据库中。但是,在导入数据以前,我们需要创建表actor(前提我们要有表结构备份,如果没有只有使用另外的工具找到表结构Percona Data Recovery Tool)看来还是需要两个工具结合使用啊。

root@localhost : sakila 23:03:50> source sakila/actor.sql
root@localhost : sakila 23:03:50> show create table actor\G
*************************** 1. row ***************************
Table: actor
Create Table: CREATE TABLE `actor` (
`actor_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`first_name` varchar(45) NOT NULL,
`last_name` varchar(45) NOT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`actor_id`),
KEY `idx_actor_last_name` (`last_name`)
) ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT CHARSET=utf8
1 row in set (0.00 sec) root@localhost : sakila 23:04:36>

现在我们导入数据,恢复actor表

[root@mysql-server-01 undrop-for-innodb]# mysql -uroot -p123456 -S /data/mysql/user_3306/mysql.sock --local-infile
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 18
Server version: 5.5.37-log MySQL Community Server (GPL) Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. root@localhost : (none) 23:17:16> use sakila
Database changed
root@localhost : sakila 23:17:19> source dumps/default/actor_load.sql;
Query OK, 0 rows affected (0.00 sec) Query OK, 600 rows affected (0.08 sec)
Records: 400 Deleted: 200 Skipped: 0 Warnings: 0 root@localhost : sakila 23:17:22>

检查恢复的数据

root@localhost : sakila 23:19:00> SELECT COUNT(*) FROM actor;
+----------+
| COUNT(*) |
+----------+
| 200 |
+----------+
1 row in set (0.00 sec) root@localhost : sakila 23:19:34> SELECT * FROM actor LIMIT 10;
+----------+------------+--------------+---------------------+
| actor_id | first_name | last_name | last_update |
+----------+------------+--------------+---------------------+
| 1 | PENELOPE | GUINESS | 2006-02-15 04:34:33 |
| 2 | NICK | WAHLBERG | 2006-02-15 04:34:33 |
| 3 | ED | CHASE | 2006-02-15 04:34:33 |
| 4 | JENNIFER | DAVIS | 2006-02-15 04:34:33 |
| 5 | JOHNNY | LOLLOBRIGIDA | 2006-02-15 04:34:33 |
| 6 | BETTE | NICHOLSON | 2006-02-15 04:34:33 |
| 7 | GRACE | MOSTEL | 2006-02-15 04:34:33 |
| 8 | MATTHEW | JOHANSSON | 2006-02-15 04:34:33 |
| 9 | JOE | SWANK | 2006-02-15 04:34:33 |
| 10 | CHRISTIAN | GABLE | 2006-02-15 04:34:33 |
+----------+------------+--------------+---------------------+
10 rows in set (0.00 sec) root@localhost : sakila 23:19:37> CHECKSUM TABLE actor;
+--------------+------------+
| Table | Checksum |
+--------------+------------+
| sakila.actor | 2472295518 |
+--------------+------------+
1 row in set (0.00 sec) root@localhost : sakila 23:19:40>

可以发现和drop table之前完全一致。到这里数据就恢复完成啦。希望小伙伴们永远不要使用到改工具。

参考资料

https://twindb.com/recover-innodb-table-after-drop-table-innodb/

DROP TABLE 恢复【一】的更多相关文章

  1. Hadoop之hive的drop table恢复

    一.引言: 快下班的时候我开发同事问能不能将hive中drop掉的数据恢复过来,我记得是有开回收站的,当时我回答说可以恢复的. 二.恢复过程: 在之前我有对hadoop的回收站有过了解,就是将hdfs ...

  2. MySQL5.7下面,误操作导致的drop table db1.tb1; 的恢复方法:

    MySQL5.7下面,误操作导致的drop table db1.tb1; 的恢复方法: 0.停业务数据写入.[iptables封禁] 1.从备份服务器上拉取最新的一个全备文件,恢复到一个临时的服务器上 ...

  3. hive drop和恢复partition external table

    在hdfs目录:/user/xx/table/test_external 保存 test_external 表数据 先建表,使用列式存储格式 CREATE external TABLE `test_e ...

  4. DROP TABLE ** CASCADE CONSTRAINTS PURGE删除表的时候级联删除从表外键

    1.关于 cascade constraints 假设A为主表(既含有某一主键的表),B为从表(即引用了A的主键作为外键). 则当删除A表时,如不特殊说明,则 drop table A 系统会出现错误 ...

  5. Oracle10g 回收站及彻底删除table : drop table xx purge

    drop后的表被放在回收站(user_recyclebin)里,而不是直接删除掉.这样,回收站里的表信息就可以被恢复,或彻底清除. 1.通过查询回收站user_recyclebin获取被删除的表信息, ...

  6. oracle drop table and purge

    一.drop表 执行drop table xx 语句 drop后的表被放在回收站(user_recyclebin)里,而不是直接删除掉.这样,回收站里的表信息就可以被恢复,或彻底清除. 通过查询回收站 ...

  7. Oracle Drop表并未直接删除 drop table xx purge

    drop表 执行drop table xx 语句     drop后的表被放在回收站(user_recyclebin)里,而不是直接删除掉.这样,回收站里的表信息就可以被恢复,或彻底清除.     通 ...

  8. Drop Table对MySQL的性能影响分析

    [问题描述] 最近碰到有台MySQL实例出现了MySQL服务短暂hang死,表现为瞬间的并发线程上升,连接数暴增. 排查Error Log文件中有page_cleaner超时的信息,引起我们的关注: ...

  9. Oracle Drop Table

    DROP TABLE 使用DROP TABLE语句将表或对象表移动到回收站或从数据库中完全删除表及其所有数据. 注:除非指定purge子句,否则drop table语句不会将表占用的空间释放回表空间供 ...

随机推荐

  1. POJ 1191棋盘分割问题

    棋盘分割问题 题目大意,将一个棋盘分割成k-1个矩形,每个矩形都对应一个权值,让所有的权值最小求分法 很像区间DP,但是也不能说就是 我们只要想好了一个怎么变成两个,剩下的就好了,但是怎么变,就是变化 ...

  2. HDU 2829 区间DP & 前缀和优化 & 四边形不等式优化

    HDU 2829 区间DP & 前缀和优化 & 四边形不等式优化 n个节点n-1条线性边,炸掉M条边也就是分为m+1个区间 问你各个区间的总策略值最少的炸法 就题目本身而言,中规中矩的 ...

  3. SRM470

    250pt 给定1个最多16颜色的字符串(颜色可以重复),甲在最左边,乙在最右边.轮流操作,每次可以消除一种颜色. 给定一个k,问谁能最先消除完到位置k之间的障碍. 思路: 每个人肯定优先取对方没有的 ...

  4. shell 命令 netstat 查看端口占用

    netstat 查看 8888端口的占用情况

  5. shell wc -l

    shell 命令之 wc -l 给出一个比较常用的命令: cat * | wc -l 查询当前文件夹下的文件的总行数. 原理就是统计了文件中换行符的数量.

  6. excel设定备选值

    excel设定备选值 有的时候我们要人为向excel中某一列添加数据,可以通过下面的方法,为这列设定备选值. 操作方法 选中excel表格的一列,选择  数据 -- 有效性 -- 允许: 选择 序列 ...

  7. MCU_存储器

    MCU的存储器用途: RAM:数据存储器,和计算机的内存差不多,主要是用来存放程序运行产生的过程数据,掉电后会丢失数据,因此程序在上电后需要进行初始化.程序中的全局变量占据着RAM中的固定空间,局部变 ...

  8. 在Delphi中处理word文档与数据库的互联

    在Delphi中处理word文档与数据库的互联 ---- 目前,Delphi被越来越多的人选中作为MIS系统开发中的前台工具.在以Delphi为前台,一些大型数据库为后台的MIS系统中,图形的处理不可 ...

  9. JS学习笔记1_基础与常识

    1.六种数据类型 5种基础的:Undefined,Null,Boolean,Number,String(其中Undefined派生自Null) 1种复杂的:Object(本质是一组无序键值对) 2.字 ...

  10. wpf APlayer 播放

    效果图: 进入 迅雷开发者中心 下载最新SDK与解码库 注:解压最新SDK,运行install.bat. 解压完美解码库将codecs文件拷贝到项目Debug下 源码地址 :链接:https://pa ...