データベースが「バラ色」でなくなったとき
システム管理者として最も嫌な瞬間は、コードのビルドエラーではなく、午前3時にデータベース破損でシステムがダウンしたという通知を受け取るときだ。以前、MyISAMで動いているサーバーで約8GBのテーブルが突然Table is marked as crashed and should be repairedというエラーを出したことがある。焦ってバックアップを探す(すでに4時間前のものだった)代わりに、mysqlcheckを実行して7分で解決した。
InnoDBとMyISAMのどちらを使っていても、定期的なメンテナンスは欠かせない。mysqlcheckはエラー修復だけでなく、断片化したディスク領域の回収や、数ヶ月にわたるINSERT/DELETEの繰り返しで古くなったインデックス統計情報の更新にも使える。
mysqlcheckとは何か、なぜ必要なのか
mysqlcheckはMySQLとMariaDBに付属するCLIユーティリティだ。簡単に言えば、CHECK TABLE、REPAIR TABLE、ANALYZE TABLE、OPTIMIZE TABLEといったSQLコマンドのラッパーである。
MySQLシェルにログインして各テーブルに対してコマンドを一つずつ実行する代わりに、ターミナルから1行実行するだけでデータベース全体、あるいはサーバー全体を処理できる。重要なのは、データベースがオンラインのまま実行できることだ。ただし、一部の重い操作はテーブルを一時的にロックするため、アクセスの少ない時間帯を選ぶこと。
実践:よく使うmysqlcheckコマンド
コマンドを実行する前に、対象テーブルに対して十分な権限を持つユーザーが必要だ。基本的な構文:
mysqlcheck [options] [db_name [table_names]]
1. データベース全体のエラーチェック
データベースの応答が異常に遅い、あるいは見慣れないエラーが返ってきたときに最初にやることだ。このコマンドでテーブル構造をスキャンし、問題が大きくなる前に早期に破損を発見できる。
# サーバー上のすべてのデータベースをチェック
mysqlcheck -u root -p --all-databases
# 特定のデータベースのみチェック
mysqlcheck -u root -p ten_database
2. 自動修復(Auto-repair)
チェックでエラーが見つかった場合(MyISAMでよく発生する)、--auto-repairフラグを追加することで同じ実行で即座に修復できる。重要な技術的注意点:InnoDBはこの方法でのREPAIR TABLEをサポートしていない。InnoDBが破損した場合は、my.cnfのinnodb_force_recoveryを使う必要があり、それはまた別の話で、はるかに複雑だ。
mysqlcheck -u root -p --auto-repair --databases ten_database
3. テーブルの最適化(Optimize)
数ヶ月の本番稼働を経ると、ログテーブルや頻繁にDELETEされるテーブルにフラグメンテーションが蓄積する。.ibdファイルが肥大化し、クエリは必要以上に多くのブロックを読み込み、ディスク容量が無駄に消費される。以前、約15GBのログテーブルにOPTIMIZEを実行したところ、即座に約4GBを回収できた。
mysqlcheck -u root -p --optimize ten_database
InnoDBの場合、MySQLはALTER TABLE ... ENGINE=InnoDBを実行してテーブルを最初から再構築する。そのためこの操作は処理中テーブルを完全にロックする。ピーク時間帯には絶対に実行しないこと。
4. テーブルの分析(Analyze)
このコマンドはインデックス統計情報を更新する。MySQL Query Optimizerが実行計画を選択する際に使用する数値だ。統計情報が古くなると、オプティマイザが誤ったインデックスを選択し、10msのクエリがフルテーブルスキャンで数秒かかるようになることがある。大規模なデータインポートやマイグレーションの後には必ずANALYZEを実行すること。
mysqlcheck -u root -p --analyze ten_database
本番運用での実践的な経験
実際にデータベース障害を何度も対応して得た知見をいくつか紹介する:
- 大きなテーブルのOptimizeはピーク時間帯に実行しない: 20GBのテーブルが数千のリクエスト処理中にロックされると、システム全体が止まる。午前2〜3時にスケジュールするか、ゼロダウンタイムが必要ならpt-online-schema-changeを使うこと。
- 複数フラグの組み合わせ: check・repair・optimizeを1回の実行にまとめて時間を節約する:
mysqlcheck -u root -p --auto-repair --check --optimize --databases my_app_db
- 突然の停電後は–fastを使う: このフラグは正しくクローズされなかったテーブルのみをチェックし、問題のないテーブルはスキップする。50以上のテーブルを持つサーバーでは、全体チェックと比べて80〜90%の時間を節約できる。
Cronjobによるメンテナンスの自動化
エラーが出るまで待ってから対応するのは防御的な姿勢として不十分だ。毎週日曜日に定期クリーンアップスクリプトを設定している。/opt/scripts/db_maintenance.shファイルを作成する:
#!/bin/bash
LOG="/var/log/db_maintenance.log"
echo "=== $(date) ===" >> "$LOG"
mysqlcheck -u root -p'YOUR_PASSWORD' --all-databases --optimize --silent >> "$LOG" 2>&1
crontabに追加する(毎週日曜日の午前3:00に実行):
0 3 * * 0 /opt/scripts/db_maintenance.sh
ログをファイルに記録しておくことで、後で障害調査が必要な場合に履歴を追跡できる。--silentフラグはエラーがある場合のみ出力する。ログがすっきりして読みやすくなる。
まとめ
mysqlcheckは洗練されたUIも派手なダッシュボードも持たない。ただのターミナルコマンドだ。しかし午前3時にデータベースがエラーを吐いているとき、そのコマンド一つがあなたと深刻な障害の間に立つ唯一のものになることがある。
repairや本格的なoptimizeの前にバックアップを取ることは絶対に外せない原則だ。そしてmysqlcheck --checkを定期的なモニタリングに組み込むこと。早期発見は常に遅い修復より安くつく。

