Percona Data Recovery Tool 单表恢复
前几天写过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 -A Database 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 exit
status
make: *** [page_parser] Error
[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_parser
和constraints_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 - -f /path/to/ibdata1
如果MySQL是5.0以后的版本,InnoDB采取的是COMPACT格式,运行以下命令:
./page_parser - -f /path/to/ibdata1
运行后,page_parser
工具会创建一个pages-<TIMESTAMP>的目录,其中TIMESTAMP是UNIX系统时间戳。在这个目录下,为每个index ID,以页的index ID创建一个子目录。例如:
[root@localhost percona-data-recovery-tool]# ./page_parser - -f /data/mysql/ibdata1
Opening file: /data/mysql/ibdata1:
ID of device containing file
inode number
protection
number of hard links
user ID of owner
group ID of owner
device ID (if special file)
total size, in bytes
blocksize for filesystem I/O
number of blocks allocated
time of last access
time of last modification
time of last status change
Size to process in bytes
Disk cache size in bytes
1.00% done. -- :: ETA(in : hours). Processing speed: B/sec
2.00% done. -- :: ETA(in : hours). Processing speed: B/sec
8.80% done. -- :: ETA(in : hours). Processing speed: B/sec
9.80% done. -- :: ETA(in : hours). Processing speed: B/sec
20.80% done. -- :: ETA(in : hours). Processing speed: B/sec
28.25% done. -- :: ETA(in : hours). Processing speed: B/sec
40.96% done. -- :: ETA(in : hours). Processing speed: B/sec
51.43% done. -- :: ETA(in : hours). Processing speed: B/sec
56.49% done. -- :: ETA(in : hours). Processing speed: B/sec
76.23% done. -- :: ETA(in : hours). Processing speed: B/sec
83.23% done. -- :: ETA(in : hours). Processing speed: B/sec
84.74% done. -- :: ETA(in : hours). Processing speed: B/sec
90.79% done. -- :: ETA(in : hours). Processing speed: B/sec
99.00% done. -- :: ETA(in : hours). Processing speed: B/sec
[root@localhost percona-data-recovery-tool]#
[root@localhost percona-data-recovery-tool]# ll pages-/FIL_PAGE_INDEX/-
total
-rw-r--r-- root root Mar : -.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 , flags , columns , indexes , appr.rows
COLUMNS: id: DATA_INT DATA_UNSIGNED DATA_BINARY_TYPE DATA_NOT_NULL len ; word: DATA_VARMYSQL DATA_NOT_NULL len ; DB_ROW_ID: DATA_SYS prtype len ; DB_TRX_ID: DATA_SYS prtype len ; DB_ROLL_PTR: DAT
A_SYS prtype len ;
INDEX: name PRIMARY, id , fields /, uniq , type
root page , appr.key vals , leaf pages , size pages
FIELDS: id DB_TRX_ID DB_ROLL_PTR word
INDEX: name word, id , fields /, uniq , type
root page , appr.key vals , leaf pages , size pages
FIELDS: word id
这里,我们恢复的是sakila库下的customer表,从上面可以获取其主键信息:
INDEX: name PRIMARY, id 374, fields /, uniq , type
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: , has_limits: FALSE,
limits: {
can_be_null: FALSE,
uint_min_val: ,
uint_max_val: 4294967295ULL
}, can_be_null: FALSE
},
{ /* */
name: "DB_TRX_ID",
type: FT_INTERNAL,
fixed_length: , can_be_null: FALSE
},
{ /* */
name: "DB_ROLL_PTR",
type: FT_INTERNAL,
fixed_length: , can_be_null: FALSE
},
{ /* varchar(50) */
name: "word",
type: FT_CHAR,
min_length: ,
max_length: , has_limits: FALSE,
limits: {
can_be_null: FALSE,
char_min_len: ,
char_max_len: ,
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= -D_LARGEFILE64_SOURCE= -D_LARGEFILE_SOURCE= -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= -D_LARGEFILE64_SOURCE= -D_LARGEFILE_SOURCE= -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= -D_LARGEFILE64_SOURCE= -D_LARGEFILE_SOURCE= -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= -D_LARGEFILE64_SOURCE= -D_LARGEFILE_SOURCE= -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= -D_LARGEFILE64_SOURCE= -D_LARGEFILE_SOURCE= -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-/FIL_PAGE_INDEX/-/
[root@localhost -]# ll
total
-rw-r--r-- root root Mar : -.page
-rw-r--r-- root root Mar : -.page
-rw-r--r-- root root Mar : -.page
-rw-r--r-- root root Mar : -.page
-rw-r--r-- root root Mar : -.page
-rw-r--r-- root root Mar : -.page
-rw-r--r-- root root Mar : -.page
-rw-r--r-- root root Mar : -.page
-rw-r--r-- root root Mar : -.page
-rw-r--r-- root root Mar : -.page
................................
................................
输入以下命令进行合并页:
[root@localhost percona-data-recovery-tool]# find pages-/FIL_PAGE_INDEX/-/ -type f -name '*.page' | sort -n | xargs cat > pages-/FIL_PAGE_INDEX/-/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 - -f pages-/FIL_PAGE_INDEX/-/-.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 - -f pages-/FIL_PAGE_INDEX/-/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 -A Database 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: 0 mysql> 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
Percona Data Recovery Tool 单表恢复的更多相关文章
- 使用Percona Data Recovery Tool for InnoDB恢复数据
运维工作中难免会发生一些误操作,当数据库表被误操作删除需要紧急恢复,或者没有备份时,Percona Data Recovery Tool for InnoDB这个工具也已提供一些便捷的恢复. 当然 ...
- Percona Data Recovery Tool for InnoDB工具恢复单表的案例
今天上班有个朋友询问我,相关Percona Data Recovery Tool for InnoDB恢复数据中的一些问题,比如说delete,没法恢复数据,原先做过类似的异常处理就,再次模拟了下相关 ...
- MySQL单表恢复方法
正休息的时候一个电话将我的睡意完全打散,“开发童鞋写update SQL的时候忘了加where条件了”,相信每一个DBA同学听到这个消息的时候都有骂街的冲动吧.万幸只是单表写花了,而不是哪位大神在DB ...
- 一次基于innobackupex备份及binlog的单表恢复操作
[环境介绍] 系统环境:Red Hat Enterprise Linux Server release 7.0 (Maipo) + Server version: 5.7.18-log MySQL C ...
- Percona Xtrabackup导出/导入单表
默认情况下,InnoDB表不能通过直接复制表文件的方式在mysql服务器之间进行移植,即便使用了innodb_file_per_table选项.而使用Xtrabackup工具可以实现此种功能,不过,此 ...
- Innodb单表数据物理恢复
本文将介绍使用物理备份恢复Innodb单表数据的方法 前言: 随着innodb的普及,innobackup也成为了主流备份方式.物理备份对于新建slave,全库恢复的需求都能从容应对. 但当面临单表数 ...
- 单表60亿记录等大数据场景的MySQL优化和运维之道
此文是根据杨尚刚在[QCON高可用架构群]中,针对MySQL在单表海量记录等场景下,业界广泛关注的MySQL问题的经验分享整理而成,转发请注明出处. 杨尚刚,美图公司数据库高级DBA,负责美图后端数据 ...
- 【转】单表60亿记录等大数据场景的MySQL优化和运维之道 | 高可用架构
此文是根据杨尚刚在[QCON高可用架构群]中,针对MySQL在单表海量记录等场景下,业界广泛关注的MySQL问题的经验分享整理而成,转发请注明出处. 杨尚刚,美图公司数据库高级DBA,负责美图后端数据 ...
- [转载] 单表60亿记录等大数据场景的MySQL优化和运维之道 | 高可用架构
原文: http://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=209406532&idx=1&sn=2e9b0cc02bdd ...
随机推荐
- React Native(十)——TextInput一点小结
11.24(后续的道路会更加漫长,一点一点总结上去吧~): 从昨天开始接触Mac,实在让自己有点“奔溃”的赶脚……老大说,“不要紧,多接触接触就好了.” 于是,我就开始了跟Mac死磕到底的准备……就先 ...
- C 预处理
http://baike.baidu.com/link?url=0mwKZRcxHuNHa_TiwXgpQPS2S-YbOGCUJVSgZ9sb-qe-G-x4oIDZpWuZqiVNBsMYA4HT ...
- 《转载》Python并发编程之线程池/进程池--concurrent.futures模块
本文转载自Python并发编程之线程池/进程池--concurrent.futures模块 一.关于concurrent.futures模块 Python标准库为我们提供了threading和mult ...
- C# - 获取类中属性的名称
用反射控制的,不过获取属性名称的方法,用方法形式获取的,不知道消耗大不大 using System; using System.Collections.Generic; using System.Li ...
- php文件的处理和操作
好长时间没有看php手册了,有些关于文件操作方面的知识点发现从没有学过,现补习一下,顺便整理一下: 1.文件的打开:fopen() 此函数的第一个参数含有要打开的文件的名称,第二个参数规定了使用哪 ...
- 【Linux基础学习】Ubuntu 常用命令大全
一.文件目录类 1.建立目录:mkdir 目录名 2.删除空目录:rmdir 目录名 3.无条件删除子目录: rm -rf 目录名 4.改变当前目录:cd 目录名 (进入用户home目录:cd ~:进 ...
- Android中Handler引起的内存泄露
在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. 1 2 3 4 5 6 7 8 9 public class SampleActivit ...
- 如何修改 Ubuntu 的字符集?
步骤: 1.编辑 local 文件 输入: vi /var/lib/locales/supported.d/local 将 zh_CN.GB2312 加入到后面,保存. 2.执行:locale-gen ...
- mysql的root的权限被控制无法授权
一.环境: MariaDB [(none)]> select version(); +----------------+ | version() | +---------------- ...
- docker搭建gitlab、Redmine
本地使用windows,setting里面切换至linux 从Docker图标的右键菜单中选中 “Switch to Linux containers ...” Docker Engine运行在Lin ...