首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL IBData 損壞/遺失時,利用 FRM+IBD 檔案恢復 InnoDB 資料完整教程

     編輯:MySQL 資料庫相關知識

MySQL InnoDB 資料恢復:從 FRM+IBD 檔案重建資料完整實戰指南

當 ibdata1 系統表空間損壞或遺失,但保留了表結構檔案 (.frm) 與獨立表空間檔案 (.ibd) 時,可通過以下流程恢復資料。**前提:必須啟用 `innodb_file_per_table=1` (獨立表空間模式)。**

核心前提檢查

-- 檢查配置
SHOW VARIABLES LIKE 'innodb_file_per_table';
-- 必須為 ON (1),否則此方法無效

-- MyISAM 表無需此流程,直接複製 .frm/.MYD/.MYI 即可

階段一:恢復表結構 (從 .frm)

步驟 1:建立乾淨臨時資料庫

CREATE DATABASE recovery_db;
USE recovery_db;

步驟 2:建立同名空表 (引擎必須為 InnoDB)

CREATE TABLE `target_table` (`id` BIGINT(20)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

步驟 3:停止 MySQL 服務

service mysqld stop

步驟 4:用原始 .frm 覆蓋新建的 .frm

cp /path/to/original/target_table.frm /var/lib/mysql/recovery_db/target_table.frm

步驟 5:啟用 InnoDB 強制恢復模式

# 編輯 my.cnf
[mysqld]
innodb_force_recovery = 1  # 1-6 遞增嘗試,1 最輕微

# 啟動 MySQL
service mysqld start

步驟 6:導出表結構

SHOW CREATE TABLE target_table;
-- 記錄完整 CREATE TABLE 語句,含索引、外鍵、分區等

階段二:恢復資料 (從 .ibd 重建表空間關聯)

步驟 1:關閉強制恢復模式

# 註釋掉 innodb_force_recovery
service mysqld restart

步驟 2:按導出結構重建表

USE recovery_db;
-- 執行上一階段獲得的 CREATE TABLE 語句

步驟 3:丟棄新建表空間 (分離 .ibd)

ALTER TABLE target_table DISCARD TABLESPACE;

步驟 4:複製原始 .ibd 到資料目錄

cp /path/to/original/target_table.ibd /var/lib/mysql/recovery_db/target_table.ibd
chown mysql:mysql /var/lib/mysql/recovery_db/target_table.ibd

步驟 5:匯入表空間 (重建關聯) - 關鍵步驟

ALTER TABLE target_table IMPORT TABLESPACE;

預期錯誤:表空間 ID 不匹配

ERROR 1030 (HY000): Got error -1 from storage engine
-- 錯誤日誌顯示:
-- InnoDB: tablespace id in file './target_table.ibd' is 112,
-- but in the InnoDB data dictionary it is 1.

核心解決:同步表空間 ID (遞增建表法)

原表空間 ID=112,新表 ID=1,需建立 111 個臨時表將字典計數器遞增至 112:

-- 在 MySQL 客戶端執行 (或寫腳本)
DELIMITER $$
CREATE PROCEDURE sync_tablespace_id(IN target_id INT)
BEGIN
    DECLARE i INT DEFAULT 1;
    WHILE i < target_id DO
        SET @sql = CONCAT('CREATE TABLE `tmp_sync_', i, '` (`id` INT) ENGINE=InnoDB');
        PREPARE stmt FROM @sql;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;
        SET i = i + 1;
    END WHILE;
END $$
DELIMITER ;

CALL sync_tablespace_id(112);  -- 目標 ID 為錯誤日誌中的數值

步驟 6:重新匯入表空間

ALTER TABLE target_table DISCARD TABLESPACE;
-- 重新複製 .ibd (上一步可能已移動)
cp /path/to/original/target_table.ibd /var/lib/mysql/recovery_db/target_table.ibd
chown mysql:mysql /var/lib/mysql/recovery_db/target_table.ibd

ALTER TABLE target_table IMPORT TABLESPACE;
-- 應成功,無錯誤

步驟 7:啟用強制恢復模式讀取資料

# my.cnf 加入
innodb_force_recovery = 1  # 1-6 遞增嘗試
service mysqld restart

# 驗證資料
SELECT * FROM target_table LIMIT 10;

步驟 8:導出資料 (mysqldump)

mysqldump -u root -p recovery_db target_table > target_table_recovered.sql

步驟 9:導入正式環境

# 新建正式資料庫
CREATE DATABASE production_db;
# 導入結構與資料
mysql -u root -p production_db < target_table_recovered.sql

批量恢復分表腳本化 (擴展)

# 批量建表同步 ID
for i in $(seq 0 111); do
    mysql -uroot -P3306 -h127.0.0.1 -Drecovery_db -e \
    "CREATE TABLE \`shard_table_$i\` (id BIGINT(20) NOT NULL AUTO_INCREMENT, PRIMARY KEY (id)) ENGINE=InnoDB";
done

# 批量丟棄表空間
for i in $(seq 0 111); do
    mysql -uroot -P3306 -h127.0.0.1 -Drecovery_db -e \
    "ALTER TABLE \`shard_table_$i\` DISCARD TABLESPACE";
done

# 複製所有 .ibd 檔案
cp /backup/shard_table_*.ibd /var/lib/mysql/recovery_db/
chown -R mysql:mysql /var/lib/mysql/recovery_db/shard_table_*.ibd

# 批量匯入表空間
for i in $(seq 0 111); do
    mysql -uroot -P3306 -h127.0.0.1 -Drecovery_db -e \
    "ALTER TABLE \`shard_table_$i\` IMPORT TABLESPACE";
done

關鍵風險與避坑指南

風險點影響對策
innodb_file_per_table=OFF無 .ibd 檔案,方法完全失效事前確認配置,定期備份 ibdata1
.frm/.ibd 不完整部分表無法恢復檔案級備份必須包含雙檔案
表空間 ID 衝突IMPORT 失敗遞增建表同步 ID (核心技巧)
強制恢復模式下寫入資料損壞風險僅用於 SELECT 導出,嚴禁寫入
大表遞增建表耗時ID 達萬級需建萬張表優化:批量建表、並行執行

預防勝於治療:備份策略建議

  1. 邏輯備份:mysqldump --single-transaction --master-data=2 每日全量
  2. 物理備份:Percona XtraBackup 熱備份 (含 .ibd + redo log)
  3. 二進位日誌:啟用 log_bin,支援時間點恢復 (PITR)
  4. 配置備份定期備份 my.cnf、.frm 結構定義
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved