mysql undrop_MySQL 如何对InnoDB使用Undrop来恢复InnoDB数据
適用于:
MySQL服務器版本4.1到5.6 [發行版4.1到5.6]
本文信息適用于所有平臺。
目標
如何使用undrop for innodb從損壞的表中提取數據
解決方案
使用工具有時可能從無法用innodb_force_recovery讀取的表中恢復數據。
undrop可以直接讀取數據庫的ibdata1文件,來獲取數據字典信息和必要的恢復信息。
通常,該工具從整個(多個)ibdata文件且/或獨立的InnoDB tablespace文件 (innodb_file_per_table在使用中的.ibd文件)提取索引頁。Blob頁被提取到可應用的另外的子目錄
一旦數據被提取到索引頁,下一步就是從數據目錄恢復主鍵或一般聚類索引ID,然后將數據提取到適于使用LOAD DATA INFILE的文件。
如果可以的話,以要恢復的(多個)數據庫的至少一個schema dump啟動,需要時使用innodb_force_recovery。即使一個過時的備份也好過什么都沒有。雖然UnDROP有時能從ibdata文件中提取一個有效表定義,它不擅于處理所有列類型。如果你完全沒有備份,.frm文件能被用于重建表定義。如果你沒有任何備份或.frm文件,那么最后一招就是UnDROP 能從idbata提取的表定義能嘗試至少恢復一些數據。
首先stream_parser是用于從ibdata提取頁的工具。它的使用很簡單:
./stream_parser -f
頁會被默認提取到”pages-”。索引頁被儲存在子目錄FIL_PAGE_INDEX,且blob頁被儲存在子目錄FIL_PAGE_TYPE_BLOB。
要提取表的所有數據,有必要識別表的主鍵的數據目錄索引ID (在沒有主鍵時的一般索引)。這能通過使用UnDROP工具的”recover_dictionary.sh”腳本,將從被提取的索引頁提取的字典數據放到在運行服務器的’test’ schema,像這樣:
$ ./recover_dictionary.sh
Generating dictionary tables dumps... OK
Creating test database ... OK
Creating dictionary tables in database test:
SYS_TABLES ... OK
SYS_COLUMNS ... OK
SYS_INDEXES ... OK
SYS_FIELDS ... OK
All OK
Loading dictionary tables data:
SYS_TABLES ... 1845 recs OK
SYS_COLUMNS ... 22029 recs OK
SYS_INDEXES ... 4994 recs OK
SYS_FIELDS ... 6070 recs OK
All OK
現在字典能被查詢來找出索引相對于任何給定表的索引ID。
給出的示例是對于在moodle2 schema中的表mdl2_user:
mysql> SELECT SYS_TABLES.NAME TABLE_NAME, SYS_TABLES.ID TABLE_ID,
SYS_INDEXES.NAME INDEX_NAME, SYS_INDEXES.ID INDEX_ID FROM SYS_TABLES LEFT JOIN
SYS_INDEXES ON SYS_TABLES.ID = SYS_INDEXES.TABLE_ID WHERE SYS_INDEXES.NAME LIKE '%PRIMARY%' AND SYS_TABLES.NAME LIKE 'moodle2/mdl2_user' AND SYS_INDEXES.NAME IN ('PRIMARY', 'GENERAL_CLUSTERED_INDEX');
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐ ‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐+
| TABLE_NAME | TABLE_ID | INDEX_NAME | INDEX_ID |
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐ ‐‐‐‐‐‐+
| moodle2/mdl2_user | 646 | PRIMARY | 1867 |
+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐‐‐‐ +‐‐‐‐‐‐‐‐‐‐+
1 row in set (0.00 sec)
INDEX_ID返回與名稱1相應的提取的頁文件:
$ ls pages‐ibdata1/FIL_PAGE_INDEX/*1867.page
pages‐ibdata1/FIL_PAGE_INDEX/0000000000001867.page
c_parser
此時有了已知的表定義,數據能被c_parser恢復,像這樣,其中mdl2_user.sql 包含表定義:
$ ./c_parser ‐b "./pages‐ibdata1/FIL_PAGE_TYPE_BLOB" ‐p "dumps/moodle2" ‐l
dumps/moodle/mdl2_user.load ‐5f pagesibdata1/
FIL_PAGE_INDEX/0000000000001867.page ‐t mdl2_user.sql
對每個schema使用以下腳本和在轉儲目錄中的給定表定義,所有在數據目錄找到的表能被提取到適合LOAD DATA INFILE的文件,以及分開的.load文件來加載它們。如果原始表定義不能被提供或從.frm文件被提取,反注釋sys_parser行只作為最后方法。如果原始表defs能被提供,它們應該被作為分開的sql文件儲存在dumps//
#!/bin/bash
RECOVERY_DB="test"
USER="root"
PASS="somepass"
DUMPS="dumps"
# Create schema
echo > ${DUMPS}/schema.sql
for DB in `mysql ‐‐user=${USER} ‐‐password=${PASS} ‐NBe "select name from
${RECOVERY_DB}.sys_tables" | sed ‐r "s/^(.*)\/.*$//" | grep ‐v SYS_ | sort ‐u `
do
mkdir ‐p ${DUMPS}/${DB}
echo "Creating schema for $DB..."
echo >> ${DUMPS}/schema.sql
echo "CREATE DATABASE IF NOT EXISTS $DB;" >> ${DUMPS}/schema.sql
for TABLE in `mysql ${RECOVERY_DB} ‐‐user=${USER} ‐‐password=${PASS} ‐NBe
"SELECT NAME FROM SYS_TABLES WHERE NAME LIKE '${DB}/%'"`
do
echo $TABLE
# ./sys_parser ‐u${USER} ‐p${PASS} ‐d ${RECOVERY_DB} ${TABLE} | tee
${DUMPS}/${TABLE}.sql >> ${DUMPS}/schema.sql
PKEY=`mysql ${RECOVERY_DB} ‐BNe "SELECT SYS_INDEXES.ID FROM SYS_TABLES
LEFT JOIN SYS_INDEXES ON (SYS_TABLES.ID = SYS_INDEXES.TABLE_ID) WHERE
SYS_TABLES.NAME = \"${TABLE}\" AND SYS_INDEXES.NAME=\"PRIMARY\""`
echo "pkey = $PKEY"
PAGE="pages‐ibdata1/FIL_PAGE_INDEX/`printf '%016u' ${PKEY}`.page"
echo "PAGE = $PAGE"
./c_parser ‐b "./pages‐ibdata1/FIL_PAGE_TYPE_BLOB" ‐p "./${DUMPS}/${DB}" ‐
l ${DUMPS}/${TABLE}.load ‐5f ${PAGE} ‐t ${DUMPS}/${TABLE}.sql > ${DUMPS}/${TABLE}
done
done
sys_parser
像之前所說的,sys_parser能被用于從ibdata文件提取表定義,但它僅應當作為最后手段。可能需要一些猜測,而且如果不能提供有效的表定義,從ibdata完整提取可用數據就不太可能了。
從.frm文件提取有效表定義
使用MySQL Utilities包的mysqlfrm從未損壞的.frm文件提取有效定義是可能的。要注意的是在診斷模式下使用mysqlfrm可能遇到與使用sys_parser從ibdata提取數據相同的問題。所以使用mysqlfrm與服務器標識是很重要的。輸出必須被調整來與c_parser運作,因為如果命令行,警告,或默認字符集信息在表定義中被找到,c_parser會終止。這里是提取表定義和單個schema.sql被用于從在給定目錄中找到的所有.frm文件創建schema(s)的方式:
#!/bin/bash
for FRM in `find ../datadir/ ‐type f ‐wholename "*frm" | sort`
do
mysqlfrm ‐‐server=root:somepass@localhost:../datadir/mysql.sock ‐‐port=33307
$FRM | extract_schema.pl
if [ ${PIPESTATUS[0]} ‐ne 0 ]; then
echo "$FRM is corrupt"
fi
done
extract_schema.pl像這樣:
!/usr/bin/perl
open (SCHEMAFILE, '>>', "schema.sql") or die "Can not write to schema.sql $!";
$schema = "";
$table = "";
while () {
$origline = $ _;
chomp;
if (/^ CREATE TABLE.*$/) {
m/.*CREATE TABLE \`(. *)\`\.\`(.*)\`[[:space:]]\(/;
$schema = $1;
$table = $2;
print "Creat ing $schema.$table\n";
unless (‐e $schema or mkdir $schem a) {
die "Unable to create dir for sche ma $schema";
}
print SCHEMAFILE "CREATE DATABASE IF NOT EXISTS $schema;\n";
print SCHEMAFILE "USE $schema;\n";
print SCHEMAFILE "$origline";
open (TABLEFILE, '>', "$schem a/$table.sql") or die "Can not write to $schema/$table.sql";
print TABLEF ILE "CREATE TABLE $table (\n";
}
else {
s/ENGINE=(.*?)[[:space:]].*/ENGINE=;/;
s/`PRIMARY`//;
s/^#.*$//;
s/^WARNING.*$//;
$origline =~ s/(.*ENGINE.*$)/;/;
$origline =~ s/^#.*$//;
$origline =~ s/^WARNING.*$//;
print SCHEMAFILE "$origline" if (!/^\s*$/);
print TABLEFILE "$_\n" if (!/^\s*$/);
}
}
盡管undrop 可用令人高興 , 但遇到必須使用它的情況是非常糟糕的。
當數據庫損壞時,它不能保證任何數據能被恢復。避免陷入這種情況的方法就是使用MySQL Enterprise Backup來定期創建可用的備份,以及至少一個復制slave。關心數據安全的聰明管理員會在遠程創建一個復制slave,將服務器的定期備份作為災難恢復的準備。
總結
以上是生活随笔為你收集整理的mysql undrop_MySQL 如何对InnoDB使用Undrop来恢复InnoDB数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (DFS or BFS)Find The
- 下一篇: linux cmake编译源码,linu