萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL ibdata 損壞/遺失時,利用 .frm + .ibd 檔案恢復 InnoDB 表資料完整教學

前置條件與限制

  • **僅限 InnoDB**,且啟用 innodb_file_per_table = 1 (獨立表空間),每表擁有獨立 .ibd。
  • MyISAM 直接複製 .MYD/.MYI/.frm 即可,無需此複雜流程。
  • 需有 .frm (表結構) 與 .ibd (資料/索引) 檔案殘留。

階段一:恢復表結構 (.frm → CREATE 陳述式)

  1. 建立全新空資料庫 recover_db (無任何表)
  2. 建立同名空表 (引擎必須 InnoDB,欄位任意):
    CREATE TABLE `target_table` (`id` BIGINT) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  3. 停止 MySQL:systemctl stop mysqld
  4. 用備份的 .frm **覆蓋** 新建表的 .frm
  5. 修改 my.cnf 加入:innodb_force_recovery = 1 (失敗遞增至 6)
  6. 啟動 MySQL:systemctl start mysqld
  7. 執行 SHOW CREATE TABLE target_table; 獲得完整建表 SQL
  8. **關閉 MySQL,註釋掉 innodb_force_recovery**

階段二:恢復資料 (.ibd 匯入)

  1. 用階段一取得的 SQL 在新資料庫建立表結構
  2. **丟棄表空間** (斷開 .ibd 關聯):
    ALTER TABLE target_table DISCARD TABLESPACE;
  3. 複製備份的 .ibd 到新表資料目錄 (權限 mysql:mysql)
  4. **匯入表空間** (重新關聯):
    ALTER TABLE target_table IMPORT TABLESPACE;
    預期會報錯:ERROR 1030 (HY000): tablespace id mismatch
  5. 查看錯誤日誌獲取 舊 tablespace_id (如 112) 與 新 tablespace_id (如 1)
  6. **同步 tablespace_id**:建立臨時表遞增計數器
    -- 需建立 (舊_id - 新_id) 次,因建表已佔 1
    -- 例:舊 112,新 1 → 需 111 次
    DELIMITER $$
    CREATE PROCEDURE sync_tablespace_id()
    BEGIN
        DECLARE i INT DEFAULT 1;
        WHILE i <= 111 DO
            SET @s = CONCAT('CREATE TABLE tmp_sync_', i, ' (id INT) ENGINE=InnoDB');
            PREPARE stmt FROM @s; EXECUTE stmt; DEALLOCATE PREPARE stmt;
            SET i = i + 1;
        END WHILE;
    END $$
    CALL sync_tablespace_id();
  7. 再次 DISCARD TABLESPACE → 複製 .ibd → IMPORT TABLESPACE (此次應成功)
  8. 若仍無法查詢資料,重新啟用 innodb_force_recovery=1..6 直到可 SELECT
  9. mysqldump 導出資料 → 匯入全新乾淨資料庫完成恢復

批量分表自動化腳本片段

# 批量建表
for i in {0..111}; do
  mysql -uroot -P3306 -h127.0.0.1 -Drecover_db -e "
    CREATE TABLE target_table_$i (id BIGINT PRIMARY KEY) ENGINE=InnoDB;
  "
done

# 批量 DISCARD
for i in {0..111}; do
  mysql -uroot -Drecover_db -e "ALTER TABLE target_table_$i DISCARD TABLESPACE;"
done

# 複製 .ibd (注意檔案權限 chown mysql:mysql)

# 批量 IMPORT
for i in {0..111}; do
  mysql -uroot -Drecover_db -e "ALTER TABLE target_table_$i IMPORT TABLESPACE;"
done

核心原理說明

InnoDB 透過 **tablespace_id** (存於 SYS_TABLESPACES 字典表) 識別 .ibd 檔案歸屬。DISCARD/IMPORT TABLESPACE 實際是修改字典與檔案的綁定關係。若 ID 不符,InnoDB 拒絕掛載以防資料損壞。建立臨時表會遞增全域計數器,使新表 ID 追上舊表 ID,完成對齊。

風險提示

  • innodb_force_recovery >= 4 可能導致資料損壞,僅作最後手段且立即導出。
  • 此法屬「搶險級」,**不可替代正規備份策略** (mysqldump/xtrabackup/主從/快照)。
  • 生產環境務必啟用 innodb_file_per_table 並定期驗證備份可恢復性。
copyright © 萬盛學電腦網 all rights reserved