mysql innodb引擎表很是規修復方法

    若是線上的MySQL生產數據庫的數據被誤刪除,而後DBA去會恢復數據的時候,發現該數據庫沒有作備份、binlog也沒有開啓的話。還有其餘手段去盡力去恢復數據嗎? percona公司提供了一個很是規的修復工具,能夠去修復表數據。固然這個工具是有限制的:html

一、僅針對innodb引擎的表
二、表的row_format必須是REDUNDANT或者COMPACT,通常建議爲COMPACT。而mysql5.7.8以上默認爲Dynamic,這個要特別注意。
三、一旦發生誤操做,須要儘快中止對事故表的寫入,將idb文件拷貝出來。
四、數據不必定老是能恢復,好比被從新寫入的狀況等

    如今在虛擬機上作下測試:
node

    一、先準備好測試表:mysql

root@localhost:mysql3306.sock  15:35:  [linzj]>show create table linzj.linzj\G
*************************** 1. row ***************************
       Table: linzj
Create Table: CREATE TABLE `linzj` (
  `ID` bigint(22) NOT NULL,
  `APP_ID` varchar(255) NOT NULL ,
  `IPADDRESS` varchar(255) NOT NULL ,
  `METHOD` varchar(255) NOT NULL ,
  `STATUS` int(11) NOT NULL ,
  `INVOKETIME` datetime NOT NULL ,
  `PARAM1` varchar(255) DEFAULT NULL,
  `PARAM2` varchar(255) DEFAULT NULL,
  `PARAM3` varchar(255) DEFAULT NULL,
  `PARAM4` varchar(255) DEFAULT NULL,
  `PARAM5` varchar(255) DEFAULT NULL,
  `INSTANCE_ID` varchar(255) DEFAULT NULL,
  `COST` int(11) DEFAULT '0',
  PRIMARY KEY (`ID`),
  KEY `idx_id` (`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)

    二、模擬誤操做,將表數據清空
sql

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)

    三、立刻備份表的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

    四、安裝工具vim

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

    五、解析ibd文件
ide

[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爲輔助索引。spa

    六、獲取表的定義

[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

    七、恢復表的數據

[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字段的信息也沒法修復出來。    

    八、倒回數據

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字段有特殊字符致使後續字段的信息也沒法修復出來。

    對有異常字符的記錄作了剔除,最後能恢復的數據其實很少,這裏我只恢復前100條的記錄。

| 112197 | lw112197 |       | 267083b86da116407435de6467ea7ad8 |        | C8CEDCB5C06D4CD899A978AF36F982F4 | 2014-10-07 00:00:00 |   -128 | NULL    | NULL      | NULL  | -2122317824 | -2139095040 | -2139095040 | -2145386464 | NULL       | NULL     |
| 112198 | lw112198 |       | af0bd3fe2af1ddadede17552d82bfb9b |        | B8E8E4D64D9547D6B10487898304CA26 | 2014-10-07 00:00:00 |   -128 | NULL    | NULL      | NULL  | -2122317824 | -2139095040 | -2139095040 | -2145386464 | NULL       | NULL     |
| 112199 | lw112199 |       | a0f8d1a649eeaa158448bb193f957f66 |        | C1FD7CBB10E045688A61B405DC65B4CC | 2014-10-07 00:00:00 |   -128 | NULL    | NULL      | NULL  | -2122317824 | -2139095040 | -2139095040 | -2145386464 | NULL       | NULL     |
| 112200 | lw112200 |       | efd80a0e27f833d1f873225be034f3cb |        | 5C6010521E0F4D7C87EC76BA08BABF7D | 2014-10-07 00:00:00 |   -128 | NULL    | NULL      | NULL  | -2122317824 | -2139095040 | -2139095040 | -2145386464 | NULL       | NULL     |
| 112201 | lw112201 |       | 1d0969bab6336865d92dd8de967877e7 |        | 22D0DCC57E244C0992002DF4DBDA7403 | 2014-10-07 00:00:00 |   -128 | NULL    | NULL      | NULL  | -2122317824 | -2139095040 | -2139095040 | -2145386464 | NULL       | NULL     |
| 112202 | lw112202 |       | dd4fcf04ab444bc1098488b2f0359d41 |        | 17F7EE34D673476FA8D1A9CC205E2625 | 2014-10-07 00:00:00 |   -128 | NULL    | NULL      | NULL  | -2122317824 | -2139095040 | -2139095040 | -2145386464 | NULL       | NULL     |

    九、總結

    綜上所述,其實該工具也並不是能夠保證100%修復數據。因此做爲一名DBA,首先要作好生產庫的數據備份,並要時不時對備份進行檢驗其有效性。只要備份在,心纔不會亂。


資料參考:

https://www.percona.com/docs/wiki/innodb-data-recovery-tool_start.html

https://www.percona.com/blog/2012/02/20/how-to-recover-deleted-rows-from-an-innodb-tablespace/

相關文章
相關標籤/搜索