Percona Data Recovery Tool for InnoDB (innodb-tools) 是開源的離線資料恢復工具組,透過解析原始 `ibdata1` 或 `.ibd` 檔案中的頁面結構,提取行記錄,**無需 MySQL Server 運行**即可恢復被 `DROP TABLE`、`TRUNCATE TABLE`、`DROP DATABASE` 刪除的資料。
| 支援 | 不支援 |
|---|---|
| InnoDB / XtraDB 表 | MyISAM 表 (需其他工具) |
| DROP TABLE / TRUNCATE / DROP DATABASE | 已被覆寫的資料頁 (需磁碟級恢復) |
| 檔案系統層面完整的 ibdata/ibd | 加密表 (需金鑰) |
| 已知表結構 (CREATE TABLE) | 全自動無人值守 (需人工判斷) |
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 zxvf percona-data-recovery-tool-for-innodb-0.5.tar.gz
cd percona-data-recovery-tool-for-innodb-0.5
# 配置 MySQL 源碼 (僅需配置,不編譯 MySQL)
cd mysql-source
./configure --without-server
cd ..
# 編譯工具
make
# 產生:page_parser、constraints_parser
# 共享表空間 (innodb_file_per_table=0)
./page_parser -5 -f /backup/mysql_20240115/ibdata1
# 獨立表空間 (innodb_file_per_table=1) - 直接用 .ibd
./page_parser -5 -f /backup/mysql_20240115/your_db/your_table.ibd
參數:`-5` = COMPACT 格式 (MySQL 5.0+),`-4` = REDUNDANT 格式 (5.0 前)。
輸出目錄:`pages-
**方法 A:InnoDB Tablespace Monitor (需 MySQL 運行、表未 DROP)**
CREATE TABLE innodb_table_monitor (id int) ENGINE=InnoDB;
# 觀察 error log 輸出,尋找目標表的 PRIMARY index id
# 例:INDEX: name PRIMARY, id 0 286 → space_id=0, index_id=286
DROP TABLE innodb_table_monitor;
**方法 B:直接處理所有 Index ID (實測可行)**
若表已 DROP 或 MySQL 不可用,直接對 `pages-*/FIL_PAGE_INDEX/*/` 所有目錄嘗試恢復,後續人工篩選有效資料。
# 需連線可用的 MySQL (可為備份庫、舊版本、空表)
./create_defs.pl --host=localhost --user=root --password=xxx --db=your_db --table=your_table > include/table_defs.h
輸出 C 結構體陣列,包含欄位名、型別、長度、是否 NULL、內部欄位 (DB_TRX_ID, DB_ROLL_PTR)。
make
# 重新編譯產生新的 constraints_parser
# 將同一 Index ID 下所有 .page 合併
find pages-/0-286/ -name '*.page' | sort -n | xargs cat > pages-/0-286/your_table_pages.concat
./constraints_parser -5 -f pages-/0-286/your_table_pages.concat > /tmp/recovered_data.tsv
輸出範例 (TSV,欄位順序對應 table_defs.h):
your_table 1 "John" "DOE" "john@example.com" 5 1 "2023-01-15 10:30:00" 1673778600
your_table 2 "Jane" "SMITH" "jane@example.com" 6 1 "2023-01-15 11:00:00" 1673780400
...
# 建立目標表 (結構需與原表一致)
CREATE TABLE `your_table_recovered` LIKE `your_table`;
# 導入 (注意欄位對應、時間戳轉換)
LOAD DATA INFILE '/tmp/recovered_data.tsv' REPLACE INTO TABLE `your_table_recovered`
FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"'
LINES STARTING BY 'your_table\t'
(id, name, surname, email, addr_id, active, created_at, @updated_ts)
SET updated_at = FROM_UNIXTIME(@updated_ts);
| 環節 | 關鍵點 | 錯誤後果 |
|---|---|---|
| 備份時機 | **發現遺失即刻備份**,延遲導致頁面被覆寫 | 資料永久不可恢復 |
| 表結構準確性 | 欄位順序、型別、長度**必須完全一致** | 解析出亂碼、欄位錯位、大量垃圾行 |
| 內部欄位 | table_defs.h **必須包含** DB_TRX_ID (6 bytes)、DB_ROLL_PTR (7 bytes) | 行解析偏移錯誤 |
| 頁面格式 | -5 (COMPACT) vs -4 (REDUNDANT) 必須匹配實際版本 | 頁面解析失敗、空輸出 |
| 垃圾行過濾 | 輸出含大量無效行,需人工/腳本篩選 (如主鍵非 0、時間合理) | 導入髒資料 |
| 大表分批 | 超大表分多個 Index ID,逐個恢復再合併 | 記憶體耗盡、處理過久 |
#!/bin/bash
# recover_innodb.sh
IBDATA=$1; DB=$2; TABLE=$3; OUT=$4
mkdir -p $OUT
# 1. 頁面解析
page_parser -5 -f $IBDATA -o $OUT/pages
# 2. 獲取表結構 (假設有可用 MySQL)
create_defs.pl -h localhost -u root -p $MYSQL_PWD -d $DB -t $TABLE > include/table_defs.h
# 3. 重編譯
make clean && make
# 4. 遍歷所有 Index ID 嘗試恢復
for idx_dir in $OUT/pages/FIL_PAGE_INDEX/*/; do
idx_id=$(basename $idx_dir)
cat $idx_dir/*.page | sort -n > $OUT/${TABLE}_${idx_id}.concat
constraints_parser -5 -f $OUT/${TABLE}_${idx_id}.concat > $OUT/${TABLE}_${idx_id}.tsv
done
# 5. 人工檢視各 .tsv 確認哪個 Index ID 為 PRIMARY,再導入
echo "請檢視 $OUT/*.tsv 確認正確資料,再手動導入"
替代方案比較
方案 優點 缺點 適用場景
innodb-tools 開源、離線、無需 MySQL 運行、支援 DROP/TRUNCATE 手動步驟多、需編譯、需已知結構、垃圾行多 誤刪表、無備份、InnoDB 檔案完整
mysqldump + Binlog 標準、可靠、點對點恢復 需備份 + Binlog 完整、表未 DROP 常規備份恢復、PITR
Percona XtraBackup 熱備份、增量、快速、官方支援 需預先部署、不支援單表恢復 (需整庫恢復再匯出) 生產環境標準備份策略
磁碟級恢復 (TestDisk/PhotoRec) 檔案系統層面、無視資料庫結構 碎片化嚴重、InnoDB 頁面難重組、成功率低 磁碟故障、檔案系統損壞
總結
`innodb-tools` 是 **「無備份、誤刪 InnoDB 表」的最後防線**。它不神奇,但提供了從原始儲存層面搶救資料的可能性。關鍵成功因素:**即時備份原始檔案、精確表結構定義、耐心篩選垃圾行**。建議所有 DBA 在測試環境預先演練完整流程,將恢復時間從「數小時摸索」壓縮至「標準化 30 分鐘內啟動恢復」。
Copyright © 程式碼之家 All Rights Reserved