問題の発生
ルーチン作業の最中にクエリが突然失敗したことはありませんか。データの代わりに、ERROR 145という不可解なメッセージが表示されることがあります。このエラーは、今でもMyISAMストレージエンジンを使用している人にとって、古典的で頭の痛い問題です。
MySQL 5.5.5でデフォルトとなり、堅牢なクラッシュリカバリシステムを備えたInnoDBとは異なり、MyISAMは脆弱です。ディスクへの書き込み中にMySQLプロセスが中断されると、破損しやすくなります。最近サーバーのディスク使用率が100%に達した、あるいは強制再起動が発生した場合、インデックスファイルが適切に閉じられず、テーブルが「クラッシュ(marked as crashed)」としてマークされた可能性があります。
クイック修正(要約)
MySQLターミナルやphpMyAdminにアクセスできますか?以下のコマンドを実行すれば、ほとんどの場合(約95%)これで解決します。
REPAIR TABLE tablename;
標準の修復で失敗した場合は、より強力な拡張修復を試してください。
REPAIR TABLE tablename EXTENDED;
なぜMyISAMテーブルはクラッシュするのか
根本的な原因を理解することは、この修復作業が毎週の雑用になるのを防ぐのに役立ちます。MyISAMは、.frm(スキーマ)、.MYD(データ)、.MYI(インデックス)の3つのファイルにデータを保存します。このエラーは、.MYIファイルのヘッダーが実際のデータと同期しなくなったときに発生します。主な原因は以下の通りです。
- 不適切なシャットダウン: 停電や、開発者がMySQLプロセスに対して
kill -9を実行した場合。 - ディスク容量不足: 5GBのテーブルを更新中にサーバーの空き容量がなくなり、インデックスが不完全な状態になった場合。
- ハードウェアの劣化: SSDの故障やRAMの不良セクタにより、ディスク上のビットが破損した場合。
- レガシーなファイル制限: 古い32ビットファイルシステムで、2GBまたは4GBのファイルサイズ制限に達した場合。
方法1:SQLによる修復(安全で簡単)
まずはこの方法を試してください。MySQLサーバーが稼働している状態で実行でき、エンジンの機能によって複雑なファイルロックも自動的に処理されます。
1. 標準修復
MySQLコンソールにログインし、対象のデータベースを選択します。
USE your_database_name;
REPAIR TABLE tablename;
出力結果のMsg_typeが「status」の行を確認してください。Msg_textが「OK」であれば、修復完了です。
2. 拡張修復
インデックスの損傷が激しく、クイック修正では対応できない場合があります。その場合、MyISAMはインデックスを1行ずつ再作成できます。時間はかかりますが、より徹底的な修復が可能です。
REPAIR TABLE tablename EXTENDED;
3. .frmファイルを使用した修復
.MYIファイルが消失している、あるいは完全に破壊されている場合は、.frmファイルに保存されているテーブル定義を使用してすべてを再構築するようにMySQLに指示できます。
REPAIR TABLE tablename USE_FRM;
方法2:コマンドラインによる修復(myisamchk)
破損が非常に深刻で、MySQLサービスが起動しなかったり、破損したテーブルをクエリするたびにクラッシュしたりすることがあります。このような場合は、Linuxシェルからmyisamchkユーティリティを使用します。
警告: myisamchkを使用する前に、必ずMySQLサービスを停止してください。稼働中のアクティブなテーブルに対してこのツールを実行すると、恒久的なデータ損失につながる恐れがあります。
# 最初にサービスを停止する
sudo systemctl stop mysql
データディレクトリ(通常は /var/lib/mysql/[データベース名]/)に移動します。
cd /var/lib/mysql/your_db_name/
myisamchk -r tablename.MYI
-rフラグは「recover(回復)」を意味します。それで解決しない場合は、処理は遅くなりますが、より慎重な「safe recovery」フラグを試してください。
myisamchk -o tablename.MYI
完了したら、データベースをオンラインに戻します。
sudo systemctl start mysql
修復の確認方法
修復後、テーブルの状態をチェックして、問題が残っていないか確認します。
CHECK TABLE tablename;
ステータスが「OK」であれば、テーブルは正常です。本番トラフィックを再開する前に、SELECT COUNT(*)を実行して、行数が想定通りであることを確認してください。
今後のクラッシュを防ぐ方法
MyISAMは何年もの間標準でしたが、現在ではほとんどのユースケースでレガシーな技術と見なされています。以下の3つのステップで、修復の繰り返しを終わらせましょう。
1. InnoDBへの移行
InnoDBはACID準拠です。手動での介入なしに、クラッシュから自動的に回復するためのRedoログを使用します。以下の1つのコマンドでテーブルエンジンを切り替えられます。
ALTER TABLE tablename ENGINE=InnoDB;
2. ディスク使用率の監視
MyISAMのクラッシュの多くは、ディスク容量が100%に達したことで発生します。ディスク使用率が80%を超えたときに通知されるよう、アラート(MonitやPrometheusなど)を設定してください。
3. 適切なシャットダウン
データベースサーバーの電源をいきなり切らないでください。必ず systemctl stop mysql や mysqladmin shutdown を使用して、MySQLがバッファをフラッシュし、インデックスヘッダーを正しく閉じるための時間を与えてください。

