【MySQL】InnoDB引擎ibdata文件損壞/刪除后使用frm和ibd文件恢復數據


參考:http://my.oschina.net/sansom/blog/179116

參考:http://www.jb51.net/article/43282.htm

注意!此方法只適用於innodb_file_per_table獨立表空間的InnoDB實例。

此種方法可以恢復ibdata文件被誤刪、被惡意修改,沒有從庫和備份數據的情況下的數據恢復,不能保證數據庫所有表數據的100%恢復,目的是盡可能多的恢復。

恢復數據前提是表結構定義文件frm可以使用,如果有下面報錯就比較麻煩,需要手動恢復frm文件。

我的鏈接:http://www.cnblogs.com/jiangxu67/p/4755097.html

150821 16:31:27 [ERROR] /usr/local/mysql51/libexec/mysqld: Incorrect information in file: './t/test1.frm'

InnoDB引擎ibdata和ibd文件結構

結構圖:https://github.com/jeremycole/innodb_diagrams

恢復原理:

因為配置innodb_file_per_table的獨立表空間后,InnoDB引擎表數據、索引保存在ibd文件,ibdata文件只負責undo、double write、insert buffer...一些環節。

當然如果MySQL是異常關閉同時ibdata損壞的情況下會丟失一部分數據,但如果數據庫是單點,那盡量能恢復多少是多少,至少比數據全部丟失好很多。

ibdata文件中有一個數據字典data dictionary,記錄的是實例中每個表在ibdata中的一個邏輯位置,而在ibd文件中也存儲着同樣的一個tablespace id,兩者必須一致InnoDB引擎才能正常加載到數據,否則會報錯:

2015-08-18 10:30:30 12571 [ERROR] InnoDB: Error: tablespace id in file ‘.\test\test1.ibd’ is 112, but in the InnoDB InnoDB: data dictionary it is 1

實際上我們對於ibdata文件中的 undo、double write、insert buffer數據可以並不擔心,我們只需要利用一個空的實例,一個干凈的ibdata文件,通過卸載和加載表空間把ibd文件與ibdata文件關聯。

恢復步驟:

准備一台新實例

1、建表,在新實例中建需要恢復表的表名臨時表。

這塊建議一次性將表都建好,可以統一檢查frm文件是否有損壞,注意字符集。

#循環建表
[root@test1 db1]$ for i in `ls | grep ".ibd" | awk -F '.' '{print $1}'`;do mysql -uroot -p -S /tmp/mysql.sock -e "use test;create table ${i} (a int)engine=innodb default charset=utf8"; done

2、停止實例,添加配置innodb_force_recovery = 6

3、替換frm文件

#備份新表frm
[root@test1 test]$ cp ./*.frm ./bak
[root@test1 test]$ ls ./bak
#刪除新表frm,將需要恢復表的frm復制到test目錄
[root@test1 test]$ rm -rf ./*.frm
[root@test1 db1]$ for i in `ls | grep ".frm" | awk -F '.' '{print $1}'`;do cp $i.frm ../db1/;done

4、啟動實例,檢查表

#循環檢查表是否能夠打開
[root@test1 db1]$ for i in `ls | grep ".ibd" | awk -F '.' '{print $1}'`;do mysql -uroot -p -S /tmp/mysql.sock -e "use test;show create table $i \G" --default-character-set=utf8 >> ./build1.txt 2>&1 ;done

如果在輸出文件中出現以下錯誤則需要修復frm文件,沒有錯誤可以繼續。修復frm見帖子開始的鏈接。

150821 16:31:27 [ERROR] /usr/local/mysql51/libexec/mysqld: Incorrect information in file: './t/test1.frm'

5、獲取ibd文件中的tablespace id

ibd文件需要hexdump打開,ibd文件的0x24,0x25位置記錄的是該表的tablespace id,我們可以通過腳本一次性獲取所有表的id。

[root@test1 db1]$ for i in `ls | grep ".ibd" | awk -F '.' '{print $1}'`;do a=`hexdump -C $i.ibd |head -n 3 |tail -n 1|awk '{print $6$7}'`;mysql -uroot -p -S /tmp/mysql.sock -e "select conv('$a',16,10)" | grep -v conv >> ./id.txt 2>&1;done

然后按照id從小到大排序,因為后面需要按照id從小到大恢復,不用反復重做新實例。

6、去掉innodb_force_recovery = 6配置,重啟生效

7、建表生成tablespace id

這里注意,如果ibd文件中的tablespace id是5001,那么就需要建5000個臨時表。

另外注意建表后系統的openfile可能會很大,需要先修改系統的參數,或者建和刪表可以一起做。

[root@test1 db1]$ for i in {1..5000};do mysql -uroot -p -S /tmp/mysql.sock -e "use tmp_table;create table table_${i} (a int)engine=innodb default charset=utf8"; done

8、建需要恢復的表結構

9、卸載表空間

alter table table_name discard tablespace;

10、替換ibd文件

11、加載表空間

alter table table_name import tablespace;

官方對於卸載表和加載表的說明:

ALTER TABLE tbl_name DISCARD TABLESPACE;
This deletes the current .ibd file, so be sure that you have a backup first. Attempting to modify the table contents while the tablespace file is discarded results in an error. You can perform the DDL operations listed in Section 14.10, “InnoDB and Online DDL” while the tablespace file is discarded.
To import the backup .ibd file back into the table, copy it into the database directory, and then issue this statement:
ALTER TABLE tbl_name IMPORT TABLESPACE;
The tablespace file need not necessarily have been created on the server into which it is imported later. In MySQL 5.6, importing a tablespace file from another server works if the both servers have GA (General Availablility) status and their versions are within the same series. Otherwise, the file must have been created on the server into which it is imported.

按照以上步驟就可以把數據讀取出來,然后使用mysqldump導出。

如果字符集不一致或者字段類型不一致可能讀取出來的數會出現數據錯誤、亂碼或者串列。

MySQL 5.6對於表結構要求很嚴格,如果字段類型與原表不一致會報錯。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM