我曾經遇到過壹個初創的互聯網公司。由於維護人員不規範的備份恢復操作,導致系統表空間文件初始化,數萬個表無法讀取。花了幾個小時才把它救出來。
當妳發現數據無法讀取時,也許數據並沒有丟失,也許DBMS找不到描述數據的信息。
背景
我們來看看下面幾個關鍵的InnoDB數據字典表,這些表保存了壹些表定義信息,在我們恢復表結構的時候需要用到。
SYS_TABLES描述InnoDB表信息create table ` SYS _ TABLES `( ` name ` varchar(255)not null default ' ',?表名' id ` bigint(20)unsigned not null default ' 0 ',?表id ` n _ cols ` int(10)DEFAULT NULL,` type ` int(10)unsigned DEFAULT NULL,` mix _ id ` bigint(20)unsigned DEFAULT NULL,` mix _ len ` int(10)unsigned DEFAULT NULL,` cluster _ name ` varchar(255)DEFAULT NULL,` space ` int(10)unsigned DEFAULT NULL,?表空間id primary key(` name `))engine = innodb default charset = Latin 1;SYS_INDEXES描述了InnoDB索引信息createtable `sys _ indexes `(?table _ id ' bigint(20)unsigned not null默認值' 0 ',對應sys_tables的id?` ID` bigint(20) unsigned NOT NULL默認為' 0 ',?索引id?name ` varchar(120)default null,索引名?N _ fields`int (10)無符號缺省null,索引包含多少個字段?` TYPE` int(10)無符號缺省NULL,?` SPACE` int(10)無符號缺省NULL,?存儲索引的表空間id?` PAGE_NO` int(10)無符號缺省NULL,?索引的根頁面id?主鍵(` TABLE_ID `,` id `))ENGINE = InnoDB DEFAULT CHARSET = Latin 1;SYS_COLUMNS描述InnoDB表createtable `sys _ columns `(?table _ id ` bigint(20)unsigned not null,對應sys_tables的id?pos ` int(10)unsigned not null,字段相對在哪裏?` name`varchar (255) defaultnull,字段名?` MTYPE` int(10)無符號默認空值,?字段編碼?Pr type `int (10)無符號缺省null,字段檢查類型?` len ' int(10)無符號缺省NULL,?字段字節長度?Prec`int (10)無符號缺省null,字段精度?主鍵(` TABLE_ID `,` pos `))ENGINE = InnoDB DEFAULT CHARSET = Latin 1;SYS_FIELDS描述字段列createtable `sys _ fields `(?` index _ id ` bigint(20)unsigned NOT NULL,?` pos ' int(10)unsigned NOT NULL,?` COL_NAME` varchar(255)默認為NULL,?主鍵(` INDEX_ID `,` pos `))ENGINE = InnoDB DEFAULT CHARSET = Latin 1;文件。/storage/inno base/include/dict 0 boot . h定義了每個字典表的索引id,id對應的頁面存儲字典表的數據。
這裏我們需要借助undelete-for-innodb工具恢復數據,該工具可以讀取表空間信息以獲取頁面並從頁面中提取數據。
# wget/chhabhaya/un drop-for-innodb/archive/master . zip # yum install-y gcc flex bison # make # make sys _ parser
# ./sys_parser讀取表結構信息
sys_parser [-h] [-u] [-p] [-d]數據庫/表
Stream_parser從ibdata1或ibd或分區表中讀取InnoDB頁面。
# ./stream _ parser必須使用-f選項指定文件用法:。/stream _ parser-f & lt;innodb _ datafile & gt[-T N:M] [-s size] [-t size] [-V|-g]?其中:-h -打印這個幫助-V還是-g?- Print debug information -s size -用於磁盤緩存的內存量(允許的示例為1G 10M)。默認100M -T -僅檢索索引id = NM的頁(N-id的高位字,M-id的低位字)-t size -要掃描的InnoDB表空間的大小。只有在解析器不能自己確定的情況下才使用它。
C_parser從innodb頁面讀取記錄,並將它們保存到壹個文件中。
# ./c_parserError:用法:。/c _ parser-4 |-5 |-6[-dDV]-f & lt;InnoDB頁面或目錄& gt-T table . SQL[-T N:M][-b & lt;外部頁面目錄& gt] ?其中-f & lt;InnoDB頁面& gt- InnoDB頁面或包含頁面的目錄(所有頁面應具有相同的index _ id)-t & lt;table.sql & gt-創建表的語句-o & lt;文件& gt-將轉儲保存在此文件中。否則打印到stdout-l & lt;文件& gt-將SQL語句保存在該文件中。否則打印到stderr -h?-打印此幫助-d?-僅處理那些有可能刪除記錄的頁面(默認值=否)-D?-僅恢復刪除的行(默認值=否)-U?-僅恢復未刪除的行(默認值= YES) -V?-詳細模式(大量調試信息)-4?- innodb_datafile采用冗余格式-5?- innodb_datafile采用緊湊格式-6?- innodb_datafile是MySQL 5.6格式的-T?-僅檢索索引id = NM(N-id的高位字,M-id的低位字)-b & lt;dir & gt-可以找到外部頁面的目錄。通常是pages-XXX/FIL _ PAGE _ TYPE _ BLOB/-I & lt;文件& gt-從& lt文件& gt。-p prefix -在LOAD DATA INFILE命令中對目錄名使用前綴
接下來,我們演示該場景的幾個數據恢復場景。
場景1:下降表
innodb_file_per_table是否啟用取決於其恢復方式。當壹個表被誤刪除時,MySQL服務應該盡快停止而不是啟動。如果innodb_file_per_table=ON,最好以只讀方式重新掛載文件系統,以防止其他進程在覆蓋數據之前將其寫入塊設備。
如果評估記錄被覆蓋,可以使用表中的壹些記錄作為關鍵字,看看是否可以從ibdata1中篩選出來。
#?grep WOODYHOFFMAN ibdata1
二進制文件ibdata1匹配
您也可以使用bvi(對於較小的文件)或hexdump -C(對於較大的文件)工具。
以表sakila.actor為例創建表` actor '(` actor _ id ` smallint(5)unsigned NOT NULL AUTO _ INCREMENT,` first _ name`varchar (45) not null,` last _ UPDATE ` TIMESTAMP NOT NULL UPDATE CURRENT_TIMESTAMP上的缺省CURRENT _ TIMESTAMP,主鍵(` actor _ id `),鍵` idx _ actor _ last _ name `( ` last _ name `))ENGINE = InnoDB AUTO _ INCREMENT = 201缺省字符集
首先,恢復表結構信息1。解析系統表空間以獲取頁面信息。
。/stream _ parser-f/var/lib/MySQL/ibdata 1
2.創建壹個新模式並導入系統字典表的DDL。
貓字典/SYS_* | mysql恢復
3.創建恢復目錄
mkdir -p轉儲/默認
4.分析系統表空間中包含的字典表信息,
。/c _ parser-4f pages-ibdata 1/FIL _ PAGE _ INDEX/0000000000001 . PAGE-t dictionary/SYS _ tables . SQL & gt;dumps/default/SYS _ TABLES 2 & gt;dumps/default/SYS _ tables . SQL ./c _ parser-4f pages-ibdata 1/FIL _ PAGE _ INDEX/0000000000002 . PAGE-t dictionary/SYS _ columns . SQL & gt;dumps/default/SYS _ COLUMNS 2 & gt;dumps/default/SYS _ columns . SQL ./c _ parser-4f pages-ibdata 1/FIL _ PAGE _ INDEX/0000000000003 . PAGE-t dictionary/SYS _ indexes . SQL & gt;dumps/default/SYS _ INDEXES 2 & gt;dumps/default/SYS _ indexes . SQL ./c _ parser-4f pages-ibdata 1/FIL _ PAGE _ INDEX/0000000000004 . PAGE-t dictionary/SYS _ fields . SQL & gt;dumps/default/SYS _ FIELDS 2 & gt;轉儲/default/SYS_FIELDS.sql
5.導入恢復的數據字典
cat轉儲/default/*。sql | mysql已恢復
6.讀取恢復的表結構信息。
。/sys_parser -pmsandbox -d恢復的sakila/actor
由於5.x版本的innodb引擎沒有完整記錄表結構信息,會丟失AUTO_INCREMENT屬性、二級索引和外鍵約束、小數精度等信息。
如果從系統中刪除MySQL版frm文件,在原用途中記錄與原表同名的frm文件,觸摸也可以讀取表結構信息和數據。如果只有frm文件,可以使用MySQL FRM-diagnostic/path/to/XXX。FRM來獲取表結構信息。連接MySQL會顯示字符集信息。
innodb_file_per_table=OFF
因為是* * *表空間共享模式,所以數據頁存儲在ibdata1中,可以從ibdata1文件中提取數據。
1.獲取表的表id。sys_table有表的表id,sys_table的索引id是1。所以從000000000000000001 . page ./c _ parser-4 dfpages-ibdata 1/fil _ page _ index/0000000000001 . page-t dictionary/sys _ tables中獲取表ID。2A000001430D4D?SYS_TABLES?“崎拉/演員”?158 ?4 ?1 0 ?0 ?"" ?0000000000B28?2A000001430D4D?SYS_TABLES?“崎拉/演員”?158 ?4 ?1 0 ?0 ?"" ?0
2.使用表id獲取表的主鍵id。sys_indexes存儲表的索引信息。innodb對組織表進行索引。查找主鍵id以查找數據。sys_indexes的索引id是3,所以從00000000000003.page中獲取主鍵id。
。/c _ parser-4Df pages-ibdata 1/FIL _ PAGE _ INDEX/0000000000003 . PAGE-t dictionary/SYS _ indexes . SQL | grep 158000000000 b28 2a 0000001430 BCA?SYS_INDEXES 158 376 "主"?1 ?3 ?0 ?429496729500000000 b28 2a 000001430 3c?SYS _ INDEXES 158 377 " idx _ actor _ last _ name " 1?0 ?0 ?429496729500000000 b28 2a 000001430 BCA?SYS_INDEXES 158 376 "主"?1 ?3 ?0 ?429496729500000000 b28 2a 000001430 3c?SYS _ INDEXES 158 377 " idx _ actor _ last _ name " 1?0 ?0 ?4294967295
3.知道了主鍵id,就可以從相應的頁面中提取表數據並生成sql文件。
。/c _ parser-4f pages-ibdata 1/FIL _ PAGE _ INDEX/00000000000376 . PAGE-t saki la/actor . SQL & gt;轉儲/默認/actor 2 & gt;轉儲/默認/actor_load.sql
4.最後,導入恢復的數據。
cat轉儲/default/*。sql | mysql sakila
點擊網頁鏈接了解更多詳情。
請點擊輸入圖片說明。