システムが安定稼働しているある日、突然MySQL Error Logに Error 1114 (HY000): The table 'users' is full と表示されることがあります。すぐに df -h で確認しても、ディスクにはまだ200GB以上の空きがある。なぜ物理的なストレージに余裕があるのに、MySQLは「満杯」だと報告するのでしょうか?
これは多くのシステム管理者(DBA)が直面する皮肉な状況です。このエラーは単なる物理容量不足ではありません。InnoDBストレージエンジンがテーブルスペース(Tablespace)という概念を通じて、どのようにストレージ空間を割り当てているかに直接関係しています。
テーブルが「満杯」になる3つの主な原因
設定を変更する前に、以下の3つのシナリオから正確な原因を特定する必要があります。
- 物理ディスク容量の不足: MySQLのデータが格納されているパーティション(通常は
/var/lib/mysql)が枯渇している。 - システムテーブルスペースの制限:
ibdata1ファイルが、設定で規定された最大サイズ(max size)に達している。 - 一時テーブル(Temporary Table)の溢れ: 重いクエリ(5〜6個の大きなテーブルを
JOINするなど)により、tmp_table_sizeの制限を超える一時ファイルが作成される。
ここでは、管理者にとって最も紛らわしい原因である2番目の項目、innodb_data_file_path に関する問題の解決に焦点を当てます。これは、サーバーの空き容量に対する管理者の感覚を狂わせるエラーです。
テーブルスペース管理戦略の選択
InnoDBにはデータを保存する2つの方法があります。最初に間違った戦略を選んでしまうと、後のメンテナンスが大きな負担になる可能性があります。
1. システムテーブルスペース(集中型 ibdata1 ファイル)
デフォルトでは、MySQLはすべてのデータベースのデータを ibdata1 という単一のファイルに集約することがあります。
- リスク: このファイルは増える一方で、減ることはありません。たとえ100GBのデータを削除しても、
ibdata1のサイズはディスク上で変わらず、無意味な空き領域(断片化)が発生します。
2. File-Per-Table (innodb_file_per_table)
各テーブルが独自の .ibd ファイルを持ちます。これがモダンなシステムの標準(ゴールデンスタンダード)です。
- メリット:
DROPやTRUNCATEを実行すると、容量が即座にOSに返却されます。サーバー間でのデータ移動や管理も非常に柔軟になります。
innodb_data_file_path の制限エラーを修正する
システムテーブルスペースを使用している場合は、my.cnf(Linux)または my.ini(Windows)の設定ファイルを確認してください。「The table is full」エラーは、多くの場合、設定行にあるハードリミットが原因で発生します。
ステップ1:現状を確認する
以下のSQLコマンドを実行して、データファイルがどのように定義されているかを確認します:
SHOW VARIABLES LIKE 'innodb_data_file_path';
もし結果が ibdata1:10M:autoextend:max:512M であれば、データファイルが512MBを超えられないことを意味します。データベースがこの上限に達すると、ディスクにテラバイト単位の空きがあっても、MySQLは書き込みを拒否します。
ステップ2:容量の壁を広げる
my.cnf を開き、innodb_data_file_path の行を探します。2つの対処法があります:
方法1:最大制限を安全なレベル(例:20GB)に引き上げる
innodb_data_file_path = ibdata1:10M:autoextend:max:20G
方法2:無制限の増分を許可する(推奨)
innodb_data_file_path = ibdata1:10M:autoextend
修正後、MySQLを再起動する必要があります。重要な注意点:初期容量の値(ここでは10M)は、ディスク上の現在の ibdata1 ファイルのサイズより小さく設定してはいけません。そうしないと、サービスが起動できなくなります。
恒久的な解決策:innodb_file_per_table への移行
以前担当したECプロジェクトでは、データベースが100GBに達し、ibdata1 ファイルのバックアップが極端に遅くなっていました。根本的な解決策は innodb_file_per_table を有効にすることです。
[mysqld] セクションに以下の設定を追加します:
[mysqld]
innodb_file_per_table = 1
ただし、この設定は新規作成されるテーブルにのみ適用されます。ibdata1 に閉じ込められている古いテーブルを「救出」するには、リビルドコマンドを実行する必要があります:
ALTER TABLE users ENGINE=InnoDB;
この操作により、users テーブルがシステムテーブルスペースから切り離され、個別の .ibd ファイルが作成されます。
一時テーブル(Temporary Table)が満杯になった場合の対処
テーブルスペースの設定に問題がないのに、大規模なレポート出力時にエラーが発生する場合、原因は一時テーブルにある可能性があります。MySQLは一時テーブルにRAMを優先的に使用し、不足するとディスクに書き込みます。
以下の2つのパラメータを確認してください:
SHOW VARIABLES LIKE 'tmp_table_size';
SHOW VARIABLES LIKE 'max_heap_table_size';
システムに十分なRAMがある場合は、これらの値を256MBまたは512MBに引き上げて、処理速度を向上させ、溢れエラーを防ぎましょう:
SET GLOBAL tmp_table_size = 256 * 1024 * 1024;
SET GLOBAL max_heap_table_size = 256 * 1024 * 1024;
データクリーンアップ時の豆知識
DELETE コマンドを実行すればディスク上のファイル容量が減ると誤解されがちですが、実際にはMySQLはその領域を「再利用可能な空き領域(free space)」としてマークするだけです。実際に容量を回収(ファイルを縮小)するには、以下を使用する必要があります:
OPTIMIZE TABLE テーブル名;
警告: このコマンドはテーブルをロック(Table Lock)します。50GB程度の大きなテーブルの場合、ディスクのI/O速度によっては15〜30分かかることがあります。ユーザーへのダウンタイムを避けるため、午前2時〜3時などの深夜帯に実行するか、gh-ost などのツールを使用することをお勧めします。
結論
「The table is full」エラーは、多くの場合、実際のデータ規模に対してデフォルト設定が低すぎることが原因です。システムをスムーズに運用するためには、innodb_file_per_table を有効にし、ibdata1 の設定から max size 制限を撤廃することを優先すべきです。InnoDBのストレージメカニズムを理解することで、トラブル発生時にも冷静かつ正確に対処できるようになります。

