﻿# 當 MySQL 的資料表使用 MyISAM 儲存引擎時要如何修復錯誤

上週我公司有台 Linux 突然 CPU 標高，且許多服務發生異常，經查發現有兩個 mysqld 程序個別耗用了 45% 左右的 CPU 時間，使用 [uptime](https://manpages.ubuntu.com/manpages/noble/man1/uptime.1.html) 查出平均負載竟然高達 100 多，我用 mysqladmin extended-status指令查不出任何異狀，接著就判斷可能是資料表毀損導致，接著我用 [myisamchk](https://manpages.ubuntu.com/manpages/noble/man1/myisamchk.1.html) 工具修復也無效，最後改用 [REPAIR TABLE](http://dev.mysql.com/doc/refman/5.1/en/repair-table.html) 語法才徹底解決問題。

發生問題時，我先下 **SELECT COUNT(\*) FROM *TableName*** 是沒問題的，資料表有正常運作，接著我再下幾個含有 WHERE 篩選條件的 SQL 指令，發現回應的訊息如下：

mysql> SELECT COUNT(\*) AS num FROM *TableName* WHERE group\_id='33984' AND deleted = 'N';  
ERROR 126 (HY000): Incorrect key file for table './*DBNAME*/*TableName*.MYI'; try to repair it

當時我是先用 **myisamchk -e /var/lib/mysql/DBNAME/\*.MYI** 檢查所有資料表，有檢查出兩個表格出問題，然後進一步使用 **myisamchk -r *TableName*.MYI** 修復資料表，修復過程並沒有說明錯誤，我以為修好了，但過一段時間資料庫又再度掛點，然後再用 **myisamchk -o -f *TableName*.MYI** 強制修復也不行，這時才想到利用 MySQL 的 [12.4.2.6. REPAIR TABLE Syntax](http://dev.mysql.com/doc/refman/5.1/en/repair-table.html) 來修復資料表。

從得知有個 **USE\_FRM** 選項，也就是當 [myisamchk](https://manpages.ubuntu.com/manpages/noble/man1/myisamchk.1.html) 無法修復 \*.MYI 索引檔時，可以用這個選項來嘗試修復並重建 \*.MYI 索引檔，執行的過程如下：

```
mysql> REPAIR TABLE TableName USE_FRM;+--------------------+--------+----------+------------------------------------------+| Table              | Op     | Msg_type | Msg_text                                 |+--------------------+--------+----------+------------------------------------------+| DBNAME.TableName   | repair | warning  | Number of rows changed from 0 to 4237067 || DBNAME.TableName   | repair | status   | OK                                       |+--------------------+--------+----------+------------------------------------------+2 rows in set (3 min 56.73 sec)
```

執行完成後，所有表格就完全修復成功，系統也不再出問題了！

不過，使用 **USE\_FRM** 選項有以下注意事項：

-   僅在 **\*.MYI 檔案遺失** 或 **索引標頭損毀** (header corrupted) 時使用，而我這次的問題就是**後者**
-   表格中原本使用 **AUTO\_INCREMENT** 的欄位數值將會被重設，可能不會跟你原來的一樣！如果你的應用程式有參考到資料的 id 可能會需要再次檢查有無問題。例如：拿資料表中的 id 來建立目錄
-   由於 **\*.MYI 索引標頭** 會紀錄資料檔 ( \*.MYD ) 是否為「[壓縮資料表](http://dev.mysql.com/doc/refman/5.0/en/compressed-format.html)」，使用 **USE\_FRM** 選項重建 \*.MYI 索引檔可能會導致資料流失，也就是說你不應該使用 **USE\_FRM** 選項重建**[壓縮資料表](http://dev.mysql.com/doc/refman/5.0/en/compressed-format.html)**。

**相關連結**

-   [6.6.3. How to Repair MyISAM Tables](http://dev.mysql.com/doc/refman/5.0/en/myisam-repair.html)
-   [12.4.2.6. REPAIR TABLE Syntax](http://dev.mysql.com/doc/refman/5.1/en/repair-table.html)
-   [13.5. The MyISAM Storage Engine](http://dev.mysql.com/doc/refman/5.1/en/myisam-storage-engine.html)
-   [13.1.3.3. Compressed Table Characteristics](http://dev.mysql.com/doc/refman/5.0/en/compressed-format.html)
-   [Repairing Database Corruption in MySQL](https://www.databasejournal.com/mysql/repairing-database-corruption-in-mysql/)
