转载自:https://www.cnblogs.com/gomysql/p/3586822.html

前几天写过update或者delete忘加where条件的数据恢复。今天介绍一款开源的MySQL数据库InnoDB数据恢复工具:innodb-tools,它通过从原始数据文件中提取表的行记录,实现从丢失的或者被毁坏的MySQL表中恢复数据。例如,当你不小心执行DROP TABLE、TRUNCATE TABLE之后,可以通过以下方式恢复数据。

在介绍innodb-tools工具进行数据恢复之前,首先明确以下几点:

1、这个工具只能对InnoDB/XtraDB表有效,而无法恢复MyISAM表

2、这个工具是以保存的MySQL数据文件进行恢复的,而不用MySQL Server运行。

3、不能保证数据总一定可被恢复。例如,被重写的数据不能被恢复,这种情况下可能需要针对系统或物理的方式来恢复,不属于本工具的范畴。

4、恢复的最好时机是当你发现数据丢失时,尽快备份MySQL数据文件。

5、使用这个工具需要手动做一些工作,并不是全自动完成的。

6、恢复过程依赖于你对丢失数据的了解程度,在恢复过程中可能需要在不同版本的数据之间做出选择。那么如果你越了解自己的数据,恢复的可能性就越大。

接下来,下面通过一个例子来介绍如何通过这个工具进行恢复。

1. 前提条件

首先,需要理解的是innodb-tools工具不是通过连接到在线的database进行数据恢复,而是通过离线拷贝数据的方式进行的。注意:不要在MySQL运行的时候,直接拷贝InnoDB文件,这样是不安全的,会影响数据恢复过程。

为了完成数据恢复,必须知道将要被恢复的表结构(列名、数据类型)。最简单的方式就是SHOW CREATE TABLE,当然后续会介绍几种可替代的方式。因此,如果有一个MySQL server作为备份,即使数据是很早的甚至表中没有记录,可以有助于使用innodb-tools工具进行恢复。不过这个不是必须的。

2.简单例子

mysql> use book;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -ADatabase changed
mysql> select count(*) from million_words;
+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.13 sec)mysql> truncate million_words;
Query OK, 0 rows affected (0.23 sec)mysql> 

3.构建工具

1、下载解压innodb-tools工具源码:

安装依赖,否则抛出如下错误:

/usr/bin/ld: cannot find -lrt
collect2: ld returned 1 exit
status
make: *** [page_parser] Error 1

[root@localhost ~]# yum install glibc-static -y

wget https://launchpad.net/percona-data-recovery-tool-for-innodb/trunk/release-0.5/+download/percona-data-recovery-tool-for-innodb-0.5.tar.gz
tar -xvf percona-data-recovery-tool-for-innodb-0.5.tar.gz -C /usr/local/

cd /usr/local
ln -s percona-data-recovery-tool-for-innodb-0.5 percona-data-recovery-tool

2、进入解压后根目录下的mysql-source目录,运行配置命令(注:不运行make命令):

[root@localhost mysql-source]# cd /usr/local/percona-data-recovery-tool/mysql-source/
[root@localhost mysql-source]# ./configure 

3、完成配置步骤后,回到解压后的根目录,运行make命令,编译生成page_parserconstraints_parser工具

[root@localhost mysql-source]# cd ..
[root@localhost percona-data-recovery-tool]# make

page_parser工具将根据InnoDB的底层实现原理,解析表的页和行结构。constraints_parser工具暂时不使用,后续还需要在定义表结构之后,重新编译生成它。

4. 提取需要的页

InnoDB页的默认大小是16K,每个页属于一个特定表中的一个特定的index。page_parser工具通过读取数据文件,根据页头中的index ID,拷贝每个页到一个单独的文件中。

如果启用了innodb_file_per_table=1,也就是独立表空间文件,那么将无法完全恢复数据,本人也已经测试过,官方文档也没有提到启用独立表空间是否可以成功,在官方文档中,是设置innodb_file_per_table=0。

参考资料如下:

http://www.percona.com/docs/wiki/innodb-data-recovery-tool:mysql-data-recovery:example_data_loss_scenario

4.1 切分页

运行page_parser工具进行切分:

如果MySQL是5.0之前的版本,InnoDB采取的是REDUNDANT格式,运行以下命令:

./page_parser -4 -f /path/to/ibdata1

如果MySQL是5.0以后的版本,InnoDB采取的是COMPACT格式,运行以下命令:

./page_parser -5 -f /path/to/ibdata1

运行后,page_parser工具会创建一个pages-<TIMESTAMP>的目录,其中TIMESTAMP是UNIX系统时间戳。在这个目录下,为每个index ID,以页的index ID创建一个子目录。例如:

[root@localhost percona-data-recovery-tool]# ./page_parser -5 -f /data/mysql/ibdata1
Opening file: /data/mysql/ibdata1:
2053            ID of device containing file
130915          inode number
33200           protection
1               number of hard links
500             user ID of owner
501             group ID of owner
0               device ID (if special file)
371195904               total size, in bytes
4096            blocksize for filesystem I/O
725000          number of blocks allocated
1394179630      time of last access
1394179669      time of last modification
1394179669      time of last status change
371195904       Size to process in bytes
104857600       Disk cache size in bytes
1.00% done. 2014-03-07 16:31:45 ETA(in 00:04 hours). Processing speed: 1237320 B/sec
2.00% done. 2014-03-07 16:28:27 ETA(in 00:01 hours). Processing speed: 3726376 B/sec
8.80% done. 2014-03-07 16:27:04 ETA(in 00:00 hours). Processing speed: 25231360 B/sec
9.80% done. 2014-03-07 16:28:22 ETA(in 00:01 hours). Processing speed: 3719168 B/sec
20.80% done. 2014-03-07 16:27:00 ETA(in 00:00 hours). Processing speed: 40819863 B/sec
28.25% done. 2014-03-07 16:27:35 ETA(in 00:00 hours). Processing speed: 6912218 B/sec
40.96% done. 2014-03-07 16:27:02 ETA(in 00:00 hours). Processing speed: 47167140 B/sec
51.43% done. 2014-03-07 16:27:03 ETA(in 00:00 hours). Processing speed: 38881628 B/sec
56.49% done. 2014-03-07 16:27:37 ETA(in 00:00 hours). Processing speed: 4698112 B/sec
76.23% done. 2014-03-07 16:27:05 ETA(in 00:00 hours). Processing speed: 73252864 B/sec
83.23% done. 2014-03-07 16:27:07 ETA(in 00:00 hours). Processing speed: 26001408 B/sec
84.74% done. 2014-03-07 16:28:00 ETA(in 00:00 hours). Processing speed: 1117388 B/sec
90.79% done. 2014-03-07 16:27:12 ETA(in 00:00 hours). Processing speed: 22452811 B/sec
99.00% done. 2014-03-07 16:27:12 ETA(in 00:00 hours). Processing speed: 30479427 B/sec
[root@localhost percona-data-recovery-tool]# 

[root@localhost percona-data-recovery-tool]# ll pages-1394180806/FIL_PAGE_INDEX/0-1
total 16
-rw-r--r-- 1 root root 16384 Mar  7 16:26 1-00000008.page

4.2 选择需要的Index ID

一般来说,我们需要根据表的主键(PRIMARY index)进行恢复,主键中包含了所有的行。以下是一些可以实现的步骤:

如果数据库仍处于运行状态,并且表没有被drop掉,那么可以启动InnoDB Tablespace Monitor,输出所有表和indexes,index IDs到MySQL server的错误日志文件。创建innodb_table_monitor表用于收集innodb存储引擎表及其索引的存储方式:

mysql> CREATE TABLE test.innodb_table_monitor (id int) ENGINE=InnoDB;
Query OK, 0 rows affected (0.31 sec)mysql> 

如果innodb_table_monitor已经存在,drop表然后重新create表。等MySQL错误日志输出后,可以drop掉这张表以停止打印输出更多的监控。一个输出的例子如下:

TABLE: name book/million_words, id 239, flags 1, columns 5, indexes 2, appr.rows 0COLUMNS: id: DATA_INT DATA_UNSIGNED DATA_BINARY_TYPE DATA_NOT_NULL len 4; word: DATA_VARMYSQL DATA_NOT_NULL len 150; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DAT
A_SYS prtype 258 len 7;INDEX: name PRIMARY, id 374, fields 1/4, uniq 1, type 3root page 16419, appr.key vals 0, leaf pages 1, size pages 1FIELDS:  id DB_TRX_ID DB_ROLL_PTR wordINDEX: name word, id 375, fields 1/2, uniq 1, type 2root page 16420, appr.key vals 0, leaf pages 1, size pages 1FIELDS:  word id

这里,我们恢复的是sakila库下的customer表,从上面可以获取其主键信息:

INDEX: name PRIMARY, id 374, fields 1/4, uniq 1, type 3

Index ID是0 374,因此我们需要恢复的InnoDB页位于0-374子目录下。

备注:参考文档原文中之描述了以上这种获取表的index ID的方法,本文在实际操作中,采取了更简单的一种方式,即直接恢复page_parser生成的所有InnoDB页。实践证明这种方法也是可行的.

5. 生成表定义

步骤4中,我们已经找到了需要的数据,接下来需要找到表结构,创建表定义,将其编译到constraints_parser中,然后使用这个工具从InnoDB页中提取表中的行。

表定义包含了表中的列、列顺序、数据类型。如果MySQL server仍处于运行且表未被drop掉,那么简单实用SHOW CREATE TABLE就可以收集到这些信息。接下来将使用这些表结构信息来创建一个C结构体标识的表定义,然后编译到constraints_parser工具。C结构体的定义存放在include/table_defs.h中。

最简单的方式是create_defs.pl Perl 脚本,连接到MySQL server,读取SHOW CREATE TABLE的结果,输出生成的表定义到标准输出。下面是个例子,其中直接将结果重定向到了include/table_defs.h中:

[root@localhost percona-data-recovery-tool]# ./create_defs.pl --host=127.0.0.1 --user=root --password=yayun --db=book --table=million_words  > include/table_defs.h

下面是生成的表定义:

#ifndef table_defs_h
#define table_defs_h// Table definitions
table_def_t table_definitions[] = {{name: "million_words",{{ /* int(10) unsigned */name: "id",type: FT_UINT,fixed_length: 4,has_limits: FALSE,limits: {can_be_null: FALSE,uint_min_val: 0,uint_max_val: 4294967295ULL},can_be_null: FALSE},{ /*  */name: "DB_TRX_ID",type: FT_INTERNAL,fixed_length: 6,can_be_null: FALSE},{ /*  */name: "DB_ROLL_PTR",type: FT_INTERNAL,fixed_length: 7,can_be_null: FALSE},{ /* varchar(50) */name: "word",type: FT_CHAR,min_length: 0,max_length: 150,has_limits: FALSE,limits: {can_be_null: FALSE,char_min_len: 0,char_max_len: 150,char_ascii_only: TRUE},can_be_null: FALSE},{ type: FT_NONE }}},
};#endif

如果需要,可以根据需要编辑修改include/table_defs.h;然后根据include/table_defs.h,重新编译constraints_parser工具:

[root@localhost percona-data-recovery-tool]# make
gcc -DHAVE_OFFSET64_T -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE=1 -D_LARGEFILE_SOURCE=1 -Wall -O3 -g -I include -I mysql-source/include -I mysql-source/innobase/include -c tables_dict.c -o lib/tables_dict.o
gcc -DHAVE_OFFSET64_T -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE=1 -D_LARGEFILE_SOURCE=1 -Wall -O3 -g -I include -I mysql-source/include -I mysql-source/innobase/include -c print_data.c -o lib/print_data.o
gcc -DHAVE_OFFSET64_T -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE=1 -D_LARGEFILE_SOURCE=1 -Wall -O3 -g -I include -I mysql-source/include -I mysql-source/innobase/include -c check_data.c -o lib/check_data.o
gcc -DHAVE_OFFSET64_T -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE=1 -D_LARGEFILE_SOURCE=1 -Wall -O3 -g -I include -I mysql-source/include -I mysql-source/innobase/include -o constraints_parser constraints_parser.c lib/tables_dict.o lib/print_data.o lib/check_data.o lib/libut.a lib/libmystrings.a
gcc -DHAVE_OFFSET64_T -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE=1 -D_LARGEFILE_SOURCE=1 -Wall -O3 -g -I include -I mysql-source/include -I mysql-source/innobase/include -static -lrt -o page_parser page_parser.c lib/tables_dict.o lib/libut.a
[root@localhost percona-data-recovery-tool]# 

6. 从页中提取行记录

6.1 合并页到一个文件

前面已经提到,我们需要恢复的index ID 0 374,包含数据的页位于pages-1394180806/FIL_PAGE_INDEX/0-374/ 目录。

[root@localhost percona-data-recovery-tool]# cd pages-1394180806/FIL_PAGE_INDEX/0-374/
[root@localhost 0-374]# ll
total 36176
-rw-r--r-- 1 root root 16384 Mar  7 16:26 104-00000306.page
-rw-r--r-- 1 root root 16384 Mar  7 16:26 106-00000309.page
-rw-r--r-- 1 root root 16384 Mar  7 16:26 107-00000310.page
-rw-r--r-- 1 root root 16384 Mar  7 16:26 109-00000312.page
-rw-r--r-- 1 root root 16384 Mar  7 16:26 110-00000314.page
-rw-r--r-- 1 root root 16384 Mar  7 16:26 11-00001416.page
-rw-r--r-- 1 root root 16384 Mar  7 16:26 112-00000316.page
-rw-r--r-- 1 root root 16384 Mar  7 16:27 11732-00016419.page
-rw-r--r-- 1 root root 16384 Mar  7 16:26 13-00016419.page
-rw-r--r-- 1 root root 16384 Mar  7 16:26 16-00003437.page................................................................

输入以下命令进行合并页:

[root@localhost percona-data-recovery-tool]# find pages-1394180806/FIL_PAGE_INDEX/0-374/ -type f -name '*.page' | sort -n | xargs cat > pages-1394180806/FIL_PAGE_INDEX/0-374/customer_pages_concatenated
[root@localhost percona-data-recovery-tool]#

生成的结果文件:pages-1394180806/FIL_PAGE_INDEX/0-374/customer_pages_concatenated,将作为constraints_parser工具的输入。

6.2 运行constraints_parser工具

下面到恢复数据最核心的步骤——运行constraints_parser工具以提取行记录。和page_parser工具一样,需要通过-5或-4参数指定InnoDB页格式(COMPACT/REDUNDANT),-f指定输入文件。

回到例子中,我们可以这样运行constraints_parser工具

我们可以这样运行constraints_parser工具(下面的命令是恢复一个单一的页,也可以直接恢复经过6.1步骤合并所有页之后的文件):

./constraints_parser -5 -f pages-1394180806/FIL_PAGE_INDEX/0-374/76-00003397.page

会输出恢复数据相关语句:

LOAD DATA INFILE '/usr/local/percona-data-recovery-tool/dumps/default/million_words' REPLACE INTO TABLE `million_words` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"' LINES STARTING BY 'million_words\t' (id, word);

既然这样,那么我们就创建dumps/default/文件夹

[root@localhost percona-data-recovery-tool]# pwd
/usr/local/percona-data-recovery-tool
[root@localhost percona-data-recovery-tool]# mkdir dumps/default -p
[root@localhost percona-data-recovery-tool]# 

恢复全部页的数据到/dumps/default/million_words

[root@localhost percona-data-recovery-tool]# ./constraints_parser -5 -f pages-1394180806/FIL_PAGE_INDEX/0-374/customer_pages_concatenated >> dumps/default/million_words

输出提示如下,省略了一些内容:

95.98% done
96.42% done
96.86% done
97.30% done
97.74% done
98.19% done
98.63% done
99.07% done
99.51% done
99.96% done
LOAD DATA INFILE '/usr/local/percona-data-recovery-tool/dumps/default/million_words' REPLACE INTO TABLE `million_words` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"' LINES STARTING BY 'million_words\t' (id, word);

7. 导入数据到数据库中

mysql> use book
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -ADatabase changed
mysql> LOAD DATA INFILE '/usr/local/percona-data-recovery-tool/dumps/default/million_words' REPLACE INTO TABLE `million_words` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"' LINES STARTING BY 'million_words\t' (id, word);
Query OK, 1062600 rows affected (14.99 sec)
Records: 1031300  Deleted: 31300  Skipped: 0  Warnings: 0mysql> select count(*) from million_words;
+----------+
| count(*) |
+----------+
|  1000000 |
+----------+
1 row in set (0.20 sec)mysql> 

可以看见数据已经恢复回来,我测试的MySQL版本如下:

mysql> select version();
+-------------+
| version()   |
+-------------+
| 5.5.25a-log |
+-------------+
1 row in set (0.00 sec)mysql> show variables like 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | OFF   |
+-----------------------+-------+
1 row in set (0.00 sec)mysql> 

希望各位小伙伴永远不需要用到此方法,备份才是王道啊!

参考资料如下:

http://www.percona.com/docs/wiki/innodb-data-recovery-tool:mysql-data-recovery:start

http://hidba.org/?p=852

转载于:https://www.cnblogs.com/liang545621/p/9450906.html

Percona Data Recovery Tool 单表恢复相关推荐

  1. MySQL单表恢复方法

    正休息的时候一个电话将我的睡意完全打散,"开发童鞋写update SQL的时候忘了加where条件了",相信每一个DBA同学听到这个消息的时候都有骂街的冲动吧.万幸只是单表写花了, ...

  2. pg插入执行成功但是没有数据_pg_lightool基于basebackup的单表恢复和块恢复

    作者简介 李传成: 瀚高软件内核研发工程师,主要研究方向为数据库的备份和恢复,对wal日志的原理和应用有较深的理解.自研了wal日志解析工具walminer.pg块恢复工具pg_lightool. 背 ...

  3. 使用EaseUS Data Recovery Wizard Mac如何恢复已丢失的数据?

    easeus data recovery wizard mac破解版适用于任何数据丢失情况:分区表,引导记录或根目录丢失或损坏,数据因病毒攻击而丢失,驱动器格式化,系统崩溃,文件因软件故障而丢失,文件 ...

  4. 12c 新特性之单表恢复

    首先要有个数据库完全备份 RMAN> list backup;List of Backup Sets ===================BS Key Type LV Size Device ...

  5. 19c新特性-rman单表恢复

    前言 在12C之前,某张表被delete.update.insert并且提交后,我们可以在时间和undo允许情况下,通过flashback找回数据:如果表被drop,并且未带purge参数时,可以通过 ...

  6. mysql ibd文件还原_MySQL单表ibd文件恢复方法详解

    前言: 随着innodb的普及,innobackup也成为了主流备份方式.物理备份对于新建slave,全库恢复的需求都能从容应对. 但当面临单表数据误删,或者单表误drop的情况,如果使用物理全备进行 ...

  7. oracle 12c recover table恢复单表

    在 Oracle 12c 之前,如果误删一张表,常规的方法是 Flashback 闪回或 TSPITR.如果需要恢复的表空间过大,TSPITR 会耗时非常久:而开启 flashback 会消耗磁盘空间 ...

  8. sql server 恢复数据库、单表数据的方法

    1.如果不小心把某个表的数据删了.不要急.进服务器看看数据库有没有备份.有的话先找出来备份文份XX.bak的 2.然后把这个XX.bak的文件复制出来.放到D盘或E盘下.不要放桌面.等一下恢复不好找 ...

  9. 单表60亿记录等大数据场景的MySQL优化和运维之道 | 高可用架构

    015-08-09 杨尚刚 高可用架构 此文是根据杨尚刚在[QCON高可用架构群]中,针对MySQL在单表海量记录等场景下,业界广泛关注的MySQL问题的经验分享整理而成,转发请注明出处. 杨尚刚,美 ...

  10. Android Data Recovery for Mac(安卓数据恢复软件)破解版安装

    1.Android Data Recovery 简介 Android Data Recovery 是 macOS 系统上一款 Android 设备数据恢复软件,能够帮助我们在 mac 电脑上对 And ...

最新文章

  1. Rhel6-mpich2 hpc集群配置文档
  2. QT中封装的IP地址的widget
  3. word List 09
  4. Workbox CLI v3.x 中文版
  5. 雅可比行列式_夏七八写:关于“斜二测画法”与雅可比行列式的关系的想法
  6. 修改固态硬盘的物理序列号_买固态怕踩坑?收下这些软件,轻松鉴别好坏
  7. mac下配置android sdk环境 安装eclipse
  8. Mysql中把varchar类型的字段转化为tinyint类型的字段
  9. VS2015激活 密钥
  10. 深度学习 | 《深度学习》“花书”知识点笔记
  11. LeetCode(查找元素的第一个和最后一个位置)
  12. 定时任务最简单的3种实现方法(超好用)
  13. 树莓派 python 驱动 lcd tft spi 2.8寸 ili9341 240x320
  14. canvas webGL SVG 比较
  15. 多语言适配分享会演讲稿
  16. RPM包安装的数据库进行版本升级
  17. 人工智能一词,正在被“夸克们”玩坏
  18. java开发可视化界面_java 可视化界面编程
  19. Invalid bound statement (not found): com.kuang.springcloud.dao.DeptDao.queryById
  20. 二手车电商三国杀,广告大战究竟该不该打?

热门文章

  1. liferay6连接mysql_Liferay 6开发学习(二十六):数据库连接相关问题
  2. 收藏+下载!Flink 社区最全学习渠道汇总
  3. 解决问题 1474 个,Flink 1.11 究竟有哪些易用性上的改善?
  4. 我35岁了,依然可以“横行职场”
  5. mysql tree 和 hash_mysql_B-tree索引和哈希索引
  6. FR多sheet的内置检验和JS校验, 数据集范围校验;填报存在时不提交并提示已存在
  7. php创建游戏房间思路,php设计模式之建造器模式分析【星际争霸游戏案例】
  8. 安装java目录不存在_从GitHub安装R packge - “'''在当前工作目录中不存在
  9. 牛客小白月赛4 J 强迫症 思维
  10. 车联网正在大跨步发展,但安全问题仍为最大难关