萬盛學電腦網

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

MySQL InnoDB 表損壞修復實戰:innodb_force_recovery 參數深度應用

故障現場

  • 從庫 MySQL 不斷重啟
  • 錯誤日誌:InnoDB: Database page corruption on disk or a failed file read of page 30506
  • 提示:index "PRIMARY" of table "maitem"."email_status" 主鍵索引頁損壞

核心工具:innodb_force_recovery

啟動參數,值 0-6,越大限制越多、容錯越強。大於 0 時進入只讀模式(不可 INSERT/UPDATE/DELETE)。

值常量行為風險
1SRV_FORCE_IGNORE_CORRUPT忽略壞頁低,可能讀到髒數據
2SRV_FORCE_NO_BACKGROUND阻止主線程 Purge中,阻塞清理
3SRV_FORCE_NO_TRX_UNDO不執行事務回滾高,事務不一致
4SRV_FORCE_NO_IBUF_MERGE不合併插入緩衝高,二級索引損壞
5SRV_FORCE_NO_UNDO_LOG_SCAN視未提交事務為已提交極高,數據不一致
6SRV_FORCE_NO_LOG_REDO不執行 Redo Log 前滾最高,數據丟失風險

修復實戰步驟(主鍵索引損壞場景)

步驟 1:最小干預啟動

# my.cnf
[mysqld]
innodb_force_recovery = 1

# 重啟
service mysql restart

服務穩定運行,可 SELECT、CREATE、DROP。

步驟 2:數據導出遷移

-- 創建同結構 MyISAM 表(避開 InnoDB 損壞頁)
CREATE TABLE email_status_bak LIKE email_status;
ALTER TABLE email_status_bak ENGINE = MyISAM;

-- 導數據(只讀模式下可 SELECT)
INSERT INTO email_status_bak SELECT * FROM email_status;

-- 刪除損壞表
DROP TABLE email_status;

# 註釋掉 innodb_force_recovery,重啟
service mysql restart

-- 重命名回原表名
RENAME TABLE email_status_bak TO email_status;

-- 可選:改回 InnoDB
ALTER TABLE email_status ENGINE = InnoDB;

關鍵點解析

  • 主鍵索引(聚簇索引)損壞比二級索引嚴重,OPTIMIZE TABLE 無效
  • ALTER TABLE ... ENGINE=MyISAM 在 force_recovery=1 下會報錯 ERROR 1025 (HY000): Error on rename,需繞過
  • 導出數據時建議分批 LIMIT,避免大事務

備選方案:數據導出重建

# 1. 導出結構+數據
mysqldump --single-transaction db_name tbl_name > tbl_dump.sql

# 2. 刪除表
DROP TABLE tbl_name;

# 3. 移除 force_recovery,重啟

# 4. 導入
mysql db_name < tbl_dump.sql

事後根因排查

  1. 硬件:smartctl -a /dev/sdX 檢查磁盤健康、RAID 卡電池、ECC 內存
  2. OS:文件系統錯誤 dmesg | grep -i error、意外斷電
  3. MySQL:innodb_flush_method=O_DIRECT、innodb_flush_log_at_trx_commit=1 確保持久化
  4. 備份:驗證備份可用性,建立 PITR 能力

避坑提醒

  • 切勿直接在生產庫嘗試 force_recovery > 1,必須在備份副本驗證
  • 修復後必須 ANALYZE TABLE 更新統計信息
  • 若涉及主從,從庫重建比修復更可靠
copyright © 萬盛學電腦網 all rights reserved