DROP TABLE 恢复【一】
当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 恢复【一】的更多相关文章
- Hadoop之hive的drop table恢复
一.引言: 快下班的时候我开发同事问能不能将hive中drop掉的数据恢复过来,我记得是有开回收站的,当时我回答说可以恢复的. 二.恢复过程: 在之前我有对hadoop的回收站有过了解,就是将hdfs ...
- MySQL5.7下面,误操作导致的drop table db1.tb1; 的恢复方法:
MySQL5.7下面,误操作导致的drop table db1.tb1; 的恢复方法: 0.停业务数据写入.[iptables封禁] 1.从备份服务器上拉取最新的一个全备文件,恢复到一个临时的服务器上 ...
- hive drop和恢复partition external table
在hdfs目录:/user/xx/table/test_external 保存 test_external 表数据 先建表,使用列式存储格式 CREATE external TABLE `test_e ...
- DROP TABLE ** CASCADE CONSTRAINTS PURGE删除表的时候级联删除从表外键
1.关于 cascade constraints 假设A为主表(既含有某一主键的表),B为从表(即引用了A的主键作为外键). 则当删除A表时,如不特殊说明,则 drop table A 系统会出现错误 ...
- Oracle10g 回收站及彻底删除table : drop table xx purge
drop后的表被放在回收站(user_recyclebin)里,而不是直接删除掉.这样,回收站里的表信息就可以被恢复,或彻底清除. 1.通过查询回收站user_recyclebin获取被删除的表信息, ...
- oracle drop table and purge
一.drop表 执行drop table xx 语句 drop后的表被放在回收站(user_recyclebin)里,而不是直接删除掉.这样,回收站里的表信息就可以被恢复,或彻底清除. 通过查询回收站 ...
- Oracle Drop表并未直接删除 drop table xx purge
drop表 执行drop table xx 语句 drop后的表被放在回收站(user_recyclebin)里,而不是直接删除掉.这样,回收站里的表信息就可以被恢复,或彻底清除. 通 ...
- Drop Table对MySQL的性能影响分析
[问题描述] 最近碰到有台MySQL实例出现了MySQL服务短暂hang死,表现为瞬间的并发线程上升,连接数暴增. 排查Error Log文件中有page_cleaner超时的信息,引起我们的关注: ...
- Oracle Drop Table
DROP TABLE 使用DROP TABLE语句将表或对象表移动到回收站或从数据库中完全删除表及其所有数据. 注:除非指定purge子句,否则drop table语句不会将表占用的空间释放回表空间供 ...
随机推荐
- day29(对象转xml(使用java))
通常使用xStream工具. 将集合,数组,对象转成XML. 导入两个包: xpp3_min-1.1.4c.jar xstream-1.4.4.jar 自定义一个类 package com.baidu ...
- Beta阶段第四篇Scrum冲刺博客-Day3
1.站立式会议 提供当天站立式会议照片一张 2.每个人的工作 (有work item 的ID),并将其记录在码云项目管理中: 昨天已完成的工作. 张晨晨:学习新的测试模块需要的东西 郭琪容:学习复习模 ...
- Java关键字、标识符、表达式、常用符号
关键字 包:package(包).import(导入) 类:class(类).enum(枚举).interface(接口).extends(继承).implements(实现) 方法:void(空). ...
- 关于cmp函数参数中的&符号
关于cmp函数参数中的&符号 关于sort函数中的cmp函数有着不同的写法,以刚刚的整形元素比较为例 还有人是这么写的: bool cmp(const int &a, const in ...
- 二分图匹配-HK算法
先把代码贴上,其他南京回来再补了.. #include <cstdio> #include <cstdlib> #include <cstring> #includ ...
- EBS-如何查看非自己提交的请求的结果
http://www.cnblogs.com/quanweiru/p/4692071.html 如何查看非自己提交的请求的结果定位要找的请求SQL举例:SELECT req.request_id, ...
- C# Winform下一个热插拔的MIS/MRP/ERP框架(简介)
Programmer普弱哥们都喜欢玩自己的框架,我也不例外. 理想中,这个框架要易于理解.易于扩展.易于维护:最重要的,易于CODING. 系统是1主体框架+N模组的多个EXE/DLL组成的,在主体框 ...
- Jmeter 结构、原理介绍
Jmeter结构.原理介绍 一.Jmeter 简介 1.是基于java语言的开源的应用软件. 2.可以进行接口测试.性能测试.接口及性能的自动化测试. 二.Jmeter体系结构 元件:可以理解为每一个 ...
- 阿里云mysql数据库备份还原
1.下载备份包 在rds的备份恢复中点击下载,在弹出的窗口中复制内网下载地址(前提是目标服务器与rds内网互通,否则请复制外网地址) 在目标服务器中执行如下命令进行下载: wget -c '复制的地址 ...
- Linux删除目录下的文件的10种方法
看到了一遍文章,便突发奇想的想起Linux中删除目录下的所有文件的方法:整理了几个,如有不足,还望读者不吝赐教! 删除当前目录下的文件 1.rm -f * #最经典的方法,删除当前目录下的所有类型的文 ...