时间:2021-07-01 10:21:17 帮助过:25人阅读
1、先准备好测试表:
- root@localhost:mysql3306.sock 15:35: [linzj]>show create table linzj.linzj\G
- *************************** 1. row ***************************
- Table: linzj
- Create Table: CREATE TABLE `linzj` (
- `INVOKE_LOG_ID` bigint(22) NOT NULL,
- `INVOKE_LOG_APP_ID` varchar(255) NOT NULL COMMENT ‘调用接口应用ID‘,
- `INVOKE_LOG_IPADDRESS` varchar(255) NOT NULL COMMENT ‘调用接口应用IP‘,
- `INVOKE_LOG_METHOD` varchar(255) NOT NULL COMMENT ‘调用接口方式‘,
- `INVOKE_LOG_STATUS` int(11) NOT NULL COMMENT ‘调用接口返回值‘,
- `INVOKE_LOG_INVOKETIME` datetime NOT NULL COMMENT ‘接口调用时间‘,
- `INVOKE_LOG_PARAM1` varchar(255) DEFAULT NULL,
- `INVOKE_LOG_PARAM2` varchar(255) DEFAULT NULL,
- `INVOKE_LOG_PARAM3` varchar(255) DEFAULT NULL,
- `INVOKE_LOG_PARAM4` varchar(255) DEFAULT NULL,
- `INVOKE_LOG_PARAM5` varchar(255) DEFAULT NULL,
- `INVOKE_LOG_INSTANCE_ID` varchar(255) DEFAULT NULL,
- `INVOKE_LOG_COST` int(11) DEFAULT ‘0‘,
- PRIMARY KEY (`INVOKE_LOG_ID`),
- KEY `idx_id` (`INVOKE_LOG_ID`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8
- 1 row in set (0.00 sec)
- root@localhost:mysql3306.sock 15:36: [linzj]>select count(*) from linzj.linzj ;
- +----------+
- | count(*) |
- +----------+
- | 10000 |
- +----------+
- 1 row in set (0.00 sec)
- root@localhost:mysql3306.sock 16:54: [linzj]>alter table linzj add index idx_cost(INVOKE_LOG_COST);alter table linzj add primary key pk_id(INVOKE_LOG_ID);
- Query OK, 0 rows affected (0.06 sec)
- Records: 0 Duplicates: 0 Warnings: 0
- root@localhost:mysql3306.sock 16:53: [linzj]>alter table linzj row_format=COMPACT;
- Query OK, 0 rows affected (0.03 sec)
- Records: 0 Duplicates: 0 Warnings: 0
- root@localhost:mysql3306.sock 16:46: [information_schema]>SELECT ROW_FORMAT from TABLES WHERE TABLE_SCHEMA=‘linzj‘ and table_name=‘linzj‘;;
- +------------+
- | ROW_FORMAT |
- +------------+
- | Compact |
- +------------+
- 1 row in set (0.10 sec)
2、模拟误操作,将表数据清空
- root@localhost:mysql3306.sock 15:37: [linzj]>truncate table linzj.linzj;
- Query OK, 0 rows affected (0.11 sec)
- root@localhost:mysql3306.sock 15:38: [linzj]>select count(*) from linzj.linzj ;
- +----------+
- | count(*) |
- +----------+
- | 0 |
- +----------+
- 1 row in set (0.00 sec)
3、马上备份表的ibd文件
- [root@mysql02 tmp]# cp /data/mysql/mysql3306/data/linzj/linzj.* /tmp/
- [root@mysql02 tmp]# ll linzj.*
- -rw-r-----. 1 root root 13463 Jul 11 15:39 linzj.frm
- -rw-r-----. 1 root root 114688 Jul 11 15:39 linzj.ibd
4、安装工具
- cd /usr/local/
- 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
- ./configure
- make
5、解析ibd文件
- [root@mysql02 percona-data-recovery-tool-for-innodb-0.5]# mv /tmp/linzj.ibd ./
- [root@mysql02 percona-data-recovery-tool-for-innodb-0.5]# ./page_parser -5 -f linzj.ibd
- Opening file: linzj.ibd:
- 2050 ID of device containing file
- 781917 inode number
- 33184 protection
- 1 number of hard links
- 0 user ID of owner
- 0 group ID of owner
- 0 device ID (if special file)
- 114688 total size, in bytes
- 4096 blocksize for filesystem I/O
- 224 number of blocks allocated
- 1499758773 time of last access
- 1499758773 time of last modification
- 1499759529 time of last status change
- 114688 Size to process in bytes
- 104857600 Disk cache size in bytes
- [root@mysql02 percona-data-recovery-tool-for-innodb-0.5]# cd page
- page_parser page_parser.c pages-1499759549/
- [root@mysql02 percona-data-recovery-tool-for-innodb-0.5]# cd page
- page_parser page_parser.c pages-1499759549/
- [root@mysql02 percona-data-recovery-tool-for-innodb-0.5]# cd pages-1499759549/
- [root@mysql02 pages-1499759549]# ll
- total 4
- drwxr-xr-x. 4 root root 4096 Jul 11 15:52 FIL_PAGE_INDEX
- [root@mysql02 pages-1499759549]# cd FIL_PAGE_INDEX/
- [root@mysql02 FIL_PAGE_INDEX]# ls
- 0-60 0-61
参数解释: -5:代表 row_format为Compact -f:代表要解析的文件
- root@localhost:mysql3306.sock 15:54: [information_schema]>select i.INDEX_ID, i.NAME FROM INNODB_SYS_INDEXES as i INNER JOIN INNODB_SYS_TABLES as t USING(TABLE_ID) WHERE t.NAME=‘linzj/linzj‘;
- +----------+---------+
- | INDEX_ID | NAME |
- +----------+---------+
- | 60 | PRIMARY |
- | 61 | idx_id |
- +----------+---------+
- 2 rows in set (0.00 sec)
此过程会将表的idb文件解析为很多的page,innodb的page分为两大部分,一部分一级索引部分(primary key),另一部分为二级索引部分(secondary key),所以解析出来的idb包括了主键数据和索引数据两大部分(如果该表有多个二级索引,则会生成多个文件)
可以知道60为主键索引的index_id,而61为辅助索引。
6、获取表的定义
- [root@mysql02 percona-data-recovery-tool-for-innodb-0.5]# ./create_defs.pl -host localhost -port 3306 -user root -password linzj -db linzj -table linzj > include/table_defs.h
- 上面的命令会将t_bibasic_storage表的表结构定义传入到table_defs.h中,然后重新make.
- [root@mysql02 percona-data-recovery-tool-for-innodb-0.5]# 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 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
7、恢复表的数据
- [root@mysql02 percona-data-recovery-tool-for-innodb-0.5]# ./constraints_parser -5 -D -f pages-1499764924/FIL_PAGE_INDEX/0-79/ > ./linzj.sql
- LOAD DATA INFILE ‘/usr/local/percona-data-recovery-tool-for-innodb-0.5/dumps/default/linzj‘ REPLACE INTO TABLE `linzj` FIELDS TERMINATED BY ‘\t‘ OPTIONALLY ENCLOSED BY ‘"‘ LINES STARTING BY ‘linzj\t‘ (INVOKE_LOG_ID, INVOKE_LOG_APP_ID, INVOKE_LOG_IPADDRESS, INVOKE_LOG_METHOD, INVOKE_LOG_STATUS, INVOKE_LOG_INVOKETIME, INVOKE_LOG_PARAM1, INVOKE_LOG_PARAM2, INVOKE_LOG_PARAM3, INVOKE_LOG_PARAM4, INVOKE_LOG_PARAM5, INVOKE_LOG_INSTANCE_ID, INVOKE_LOG_COST);
- [root@mysql02 percona-data-recovery-tool-for-innodb-0.5]# vim linzj.sql
- linzj 9893202823 "CMMAIL@MSS.CMCC" "172.16.115.7" "authenticateUserByPassword" 0 "201
- 7-05-01 00:00:01" "yusgs@js.cmcccmm" "ail@mss.cmcc***" "***n/a" "n/a" "172" ".16.112
- .23:8080<80> -1844313341
- linzj 9893202825 "CMMAIL@MSS.CMCC" "172.16.115.10" "authenticateUserByPassword" 0 "201
- 7-05-01 00:00:01" "ghaijing_lf@he.cmcccmm" "ail@mss.cmcc***" "***n/a" "n/a" "172"
- ".16.112.40:8080<80> -1777204477
参数: -5 -f的参数和page_parser相同; -D:该参数的含义为代表恢复删除的数据页
从sql文件中看出,该工具有bug,对mysql5.6以上的datetime字段类型并不支持,需要对工具做下修改。具体可以参考:https://bugs.launchpad.net/percona-data-recovery-tool-for-innodb/+bug/1190976 , 重新make后生成的sql文件如下:
- [root@mysql02 percona-data-recovery-tool-for-innodb-0.5]# vim linzj.sql
- linzj 9893202823 "CMMAIL@MSS.CMCC" "172.16.115.7" "authenticateUserByPassword" 0 "201
- 7-05-01 00:00:01" "yusgs@js.cmcccmm" "ail@mss.cmcc***" "***n/a" "n/a" "172" ".16.112
- .23:8080<80> -1844313341
- linzj 9893202825 "CMMAIL@MSS.CMCC" "172.16.115.10" "authenticateUserByPassword" 0 "201
- 7-05-01 00:00:01" "ghaijing_lf@he.cmcccmm" "ail@mss.cmcc***" "***n/a" "n/a" "172"
- ".16.112.40:8080<80> -1777204477
从中可以看出,修改了print_data.c后,已经能正常展现出datetime类型的字段明细。但是INVOKE_LOG_INSTANCE_ID字段填充非常规的符号导致生成的sql文件异常,也就是说,该字段的信息无法修复,也导致了后面的INVOKE_LOG_COST字段的信息也无法修复出来。
8、倒回数据
- root@localhost:mysql3306.sock 17:26: [linzj]>LOAD DATA INFILE ‘/tmp/linzj.sql‘ REPLACE INTO TABLE `linzj` FIELDS TERMINATED BY ‘\t‘ OPTIONALLY ENCLOSED BY ‘"‘ LINES STARTING BY ‘linzj\t‘ (INVOKE_LOG_ID, INVOKE_LOG_APP_ID, INVOKE_LOG_IPADDRESS, INVOKE_LOG_METHOD, INVOKE_LOG_STATUS, INVOKE_LOG_INVOKETIME, INVOKE_LOG_PARAM1, INVOKE_LOG_PARAM2, INVOKE_LOG_PARAM3, INVOKE_LOG_PARAM4, INVOKE_LOG_PARAM5, INVOKE_LOG_INSTANCE_ID, INVOKE_LOG_COST);
- ERROR 1300 (HY000): Invalid utf8 character string: ‘".16.112.47:8080‘
这里的报错就是因为INVOKE_LOG_INSTANCE_ID字段有特殊字符导致后续字段的信息也无法修复出来。
9、总结
综上所述,其实该工具也并非可以保证100%修复数据。所以作为一名DBA,首先要做好生产库的数据备份,并要时不时对备份进行检验其有效性。只要备份在,心才不会乱。希望永远都不会在生产库上用上这个工具。
本文出自 “林志坚的博客” 博客,请务必保留此出处http://linzhijian.blog.51cto.com/1047212/1946409
Percona Data Recovery Tool for InnoDB--mysql innodb引擎表非常规修复工具
标签:mysql innodb recovery