當 ibdata1 系統表空間損壞或遺失,但保留了表結構檔案 (.frm) 與獨立表空間檔案 (.ibd) 時,可通過以下流程恢復資料。**前提:必須啟用 `innodb_file_per_table=1` (獨立表空間模式)。**
-- 檢查配置
SHOW VARIABLES LIKE 'innodb_file_per_table';
-- 必須為 ON (1),否則此方法無效
-- MyISAM 表無需此流程,直接複製 .frm/.MYD/.MYI 即可
CREATE DATABASE recovery_db;
USE recovery_db;
CREATE TABLE `target_table` (`id` BIGINT(20)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
service mysqld stop
cp /path/to/original/target_table.frm /var/lib/mysql/recovery_db/target_table.frm
# 編輯 my.cnf
[mysqld]
innodb_force_recovery = 1 # 1-6 遞增嘗試,1 最輕微
# 啟動 MySQL
service mysqld start
SHOW CREATE TABLE target_table;
-- 記錄完整 CREATE TABLE 語句,含索引、外鍵、分區等
# 註釋掉 innodb_force_recovery
service mysqld restart
USE recovery_db;
-- 執行上一階段獲得的 CREATE TABLE 語句
ALTER TABLE target_table DISCARD TABLESPACE;
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;
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=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 為錯誤日誌中的數值
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;
-- 應成功,無錯誤
# my.cnf 加入
innodb_force_recovery = 1 # 1-6 遞增嘗試
service mysqld restart
# 驗證資料
SELECT * FROM target_table LIMIT 10;
mysqldump -u root -p recovery_db target_table > target_table_recovered.sql
# 新建正式資料庫
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 達萬級需建萬張表 | 優化:批量建表、並行執行 |
mysqldump --single-transaction --master-data=2 每日全量log_bin,支援時間點恢復 (PITR)my.cnf、.frm 結構定義