萬盛學電腦網

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

MySQL 資料表損壞:原因分析、預防策略與 MyISAM/InnoDB 修復全流程

損壞根因分類

類別典型原因影響引擎
硬體/基礎設施斷電、磁碟壞軌、RAID 降級、記憶體 ECC 錯誤、網路儲存中斷全部
作業系統/檔案系統強制關機、kill -9、檔案系統錯誤 (ext4/xfs 損壞)、inode 耗盡、磁碟滿全部
MySQL 進程寫入時進程崩潰 (OOM Killer、Segmentation Fault)、myisamchk 與 mysqld 並發操作同表MyISAM 高風險,InnoDB 有保護機制
軟體缺陷MySQL Bug (如索引構建、線上 DDL、複製)、第三方插件視版本
人為操作誤刪檔案、錯誤 TRUNCATE、複製檔案時資料庫運行全部

損壞徵兆識別

  • ERROR 145 (HY000): Table '...' is marked as crashed and should be repaired
  • ERROR 1034 (HY000): Incorrect key file for table '...'; try to repair it
  • 查詢返回行數少於預期、CHECKSUM TABLE 不一致。
  • Can't open file: '...MYI' (errno: 145) (MyISAM 索引檔損壞)。
  • InnoDB:InnoDB: corruption of data/index、assertion failure、啟動時 innodb_force_recovery 相關錯誤。

預防策略:分層防禦

  1. 硬體層:RAID 1/10 + BBU、ECC 記憶體、UPS + 優雅關機腳本、磁碟健康監控 (SMART、MegaCLI/StorCLI)。
  2. OS 層:noatime 掛載、deadline/noop I/O 調度器、預留 20% 磁碟空間、ulimit -n 65535。
  3. MySQL 配置:
    • innodb_flush_log_at_trx_commit=1、sync_binlog=1 (雙 1 保證 ACID)。
    • innodb_file_per_table=ON、innodb_page_size=16384 (預設)。
    • 定期 ANALYZE TABLE 更新統計資訊、CHECK TABLE 偵測損壞。
  4. 備份層:每日全量 + 每小時增量 (Binlog/XtraBackup)、異地儲存、定期恢復演練。
  5. 運維規範:嚴禁 kill -9,停機先 mysqladmin shutdown;myisamchk 僅在停機維護窗口執行。

MyISAM 表修復標準流程

階段 1:檢查 (離線/線上)

# 線上 (僅讀檢查,不修復)
CHECK TABLE tbl_name [FAST | MEDIUM | EXTENDED | CHANGED];

# 離線 (需停庫,最徹底)
myisamchk -e /var/lib/mysql/db/tbl_name.MYI
# -e: extend check, -m: medium, -F: fast

階段 2:標準修復 (線上/離線)

# 線上 (MySQL 5.0+)
REPAIR TABLE tbl_name [QUICK] [EXTENDED] [USE_FRM];

# QUICK: 僅修復索引樹 (極快),資料檔假設完整
# EXTENDED: 逐鍵重建索引 (慢),適用索引嚴重損壞
# USE_FRM: 僅用 .frm 重建表結構 (最後手段)

# 離線 (最快、最徹底)
myisamchk -r -q /path/tbl_name.MYI   # 快速修復 (修索引)
myisamchk -r /path/tbl_name.MYI      # 標準修復 (重建索引、清理已刪行)
myisamchk --safe-recover /path/tbl_name.MYI # 安全模式 (舊演算法,處理極端損壞)

※ 修復前**必備份 .MYD/.MYI/.frm**;sort_buffer_size、key_buffer_size 設為可用記憶體 25% 加速排序。

階段 3:索引檔頭損壞/遺失 (重建索引)

# 1. 備份資料檔
cp /var/lib/mysql/db/tbl_name.MYD /backup/

# 2. 利用 .frm 重建空表結構
mysql -e "USE db; SET AUTOCOMMIT=1; TRUNCATE TABLE tbl_name;"

# 3. 覆蓋資料檔
cp /backup/tbl_name.MYD /var/lib/mysql/db/

# 4. 修復索引
myisamchk -r -q /var/lib/mysql/db/tbl_name.MYI
# 或 REPAIR TABLE tbl_name USE_FRM

階段 4:.frm 也損壞 (極罕見)

  1. 從備份恢復 .frm → 回階段 3。
  2. 無備份但知結構:在其他庫建同結構表 → 複製 .frm/.MYI → 回階段 3。

InnoDB 表修復:innodb_force_recovery 分級救援

InnoDB 為事務引擎,崩潰恢復自動進行 (Redo Log 前滾 + Undo Log 回滾)。損壞通常指**資料頁檢驗和失敗**、**索引樹結構破損**、**系統表空間損壞**。

分級模式 (值越大限制越多,包含較小值所有限制)

級別常數行為適用場景
1SRV_FORCE_IGNORE_CORRUPT忽略損壞頁,讓 SELECT * 跳過壞頁繼續導出輕微頁損壞,優先導出資料
2SRV_FORCE_NO_BACKGROUND阻止主執行緒 (Purge、Merge) 背景操作背景操作導致崩潰
3SRV_FORCE_NO_TRX_UNDO不執行事務回滾 (視未提交為已提交)Undo Log 損壞導致啟動失敗
4SRV_FORCE_NO_IBUF_MERGE禁用插入緩衝合併、不計算統計資訊Change Buffer 損壞,**生產最高推薦 ≤4**
5SRV_FORCE_NO_UNDO_LOG_SCAN不掃描 Undo Log,視未提交為已提交Undo Log 嚴重損壞,資料一致性風險大
6SRV_FORCE_NO_LOG_REDO不做 Redo Log 前滾,資料庫頁停留在舊狀態極端災難,**資料可能大量遺失**

操作步驟

  1. 編輯 my.cnf:[mysqld] innodb_force_recovery = 4 (建議從 1 遞增測試)。
  2. 啟動服務:systemctl start mysqld。
  3. 導出資料:mysqldump --single-transaction --quick --hex-blob --routines --triggers db_name > dump.sql (若特定表報錯,單獨導出其他表)。
  4. 建立新實例/新表空間,匯入 dump.sql。
  5. 移除 innodb_force_recovery,正常啟動驗證。

※ innodb_force_recovery > 0 時,**禁止寫入操作** (INSERT/UPDATE/DELETE 會報錯)。

終極建議

**備份是唯一靠譜的修復手段。** 任何修復操作都有資料遺失風險。建立完備的備份體系 (全量+增量+異地+演練) 遠比研究修復命令更有價值。

copyright © 萬盛學電腦網 all rights reserved