MySQLエラー1118の修正:行サイズが大きすぎます (> 8126)

intermediate🗄️ MySQL2026-04-07| MySQL 5.6, 5.7, 8.0+, MariaDB, Linux/Windows/Docker環境(InnoDBストレージエンジン使用時)。

Error Message

ERROR 1118 (42000): Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.
#mysql#行サイズ#innodb#スキーマ#テーブル設計

問題の概要データベースの移行中や、ユーザープロファイルテーブルに新機能を追加している最中に、MySQLが突然停止することがあります。これは通常、テーブルが広くなりすぎた場合、つまり数十個の VARCHAR カラムがあったり、大きな固定幅フィールドがいくつか存在したりする場合に発生します。テーブルが空であっても、MySQLはスキーマ定義に基づいて行の最大 潜在的 サイズを計算します。その計算が合わない場合、プロセスは失敗します。

具体的なエラーは次のようなものです。

ERROR 1118 (42000): Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.

原因内部的には、InnoDBはデータを「ページ」と呼ばれる16KBのチャンクで管理しています。操作を高速に保つため、MySQLはすべてのページに少なくとも2行が収まることを要求します。内部ヘッダーやシステムデータに使用される126バイトを差し引くと、1行あたり正確に8,126バイトという厳格な制限が残ります。

文字セットはこの制限に達しやすくします。utf8mb4 を使用する場合、MySQLは潜在的な文字ごとに4バイトを予約します。10個の VARCHAR(255) カラムを持つテーブルは、技術的に $10 \times 255 \times 4 = 10,200$ バイトを要求します。これは、IDやタイムスタンプを追加する前ですら、すでに制限を2,000バイト超えています。

デバッグ手順まず、テーブルが現在どの行フォーマットを使用しているかを確認します。特定のテーブルのメタデータを表示するには、次のコマンドを実行してください。

SHOW TABLE STATUS LIKE 'your_table_name'\G

次に、グローバルなInnoDB環境変数を確認します。これらの設定は、MySQLが行のオーバーフローと厳密さをどのように処理するかを決定します。

SHOW VARIABLES LIKE 'innodb_strict_mode';
SHOW VARIABLES LIKE 'innodb_file_per_table';
SHOW VARIABLES LIKE 'innodb_default_row_format';

innodb_strict_modeON の場合、MySQLはサイズ制限を超える可能性のあるテーブルの作成をブロックします。ROW_FORMATCOMPACT または REDUNDANT に設定されている場合、これらの古いフォーマットはより多くのデータを8KBのページ内に直接保存するため、このエラーが発生しやすくなります。

解決策### 1. 行フォーマットを DYNAMIC に変更するDYNAMIC 行フォーマットへの変更は、最も信頼できる修正方法です。これは、かさばる荷物を貨物室に移すようなものだと考えてください。古いフォーマットはすべてをメインの行に詰め込もうとしますが、DYNAMIC は長い可変長データをオフページに移動させます。メインの行にはわずか20バイトのポインタのみを残すため、行を軽量に保つことができます。

新規テーブルの場合:

CREATE TABLE wide_table (
    id INT PRIMARY KEY,
    col1 VARCHAR(500),
    col2 VARCHAR(500),
    ...
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;

既存のテーブルの場合:

ALTER TABLE table_name ROW_FORMAT=DYNAMIC;

2. VARCHAR を TEXT または BLOB に変換する特定のカラムがスキーマを肥大化させている場合は、それらを TEXT または BLOB に変換してみてください。VARCHAR とは異なり、これらの型は自動的にオフページ・ストレージの対象となります。これは、インデックスを作成する必要のない広いカラムが20〜30個ある場合に特に有効です。

-- 広い VARCHAR を TEXT に変換する
ALTER TABLE table_name MODIFY column_name TEXT;

古いMySQLバージョンでは、TEXT カラムにデフォルト値を設定できないことに注意してください。短い識別子ではなく、大きなコンテンツブロックに使用してください。

3. InnoDB Strict Mode を無効にする(一時的な回避策)厳密モードをオフにすることで、MySQLに広いテーブルを強制的に受け入れさせることができます。これは「自己責任」の回避策です。ALTER コマンドは成功しますが、後で制限を超える実際のデータを INSERT しようとしたときに、依然としてエラーが発生する可能性があります。

-- 現在のセッションのみ無効化
SET SESSION innodb_strict_mode = 0;

-- グローバルに無効化(SUPER権限が必要)
SET GLOBAL innodb_strict_mode = 0;

4. 文字セットを最適化する絵文字や国際的なテキストをサポートする場合、utf8mb4 を使用するのが標準ですが、行サイズの面ではコストがかかります。カラムに内部ステータスコードや英数字のIDのみを保存する場合は、latin1 に切り替えることで、1文字あたりの使用量を4バイトからわずか1バイトに削減できます。

検証手順変更を適用した後、テーブルが安定しており、準拠していることを確認します。

  • CREATE または ALTER コマンドを再実行します。1118エラーが発生せずに終了するはずです。- 有効な行フォーマットを再確認します。 SELECT table_name, row_format FROM information_schema.tables WHERE table_schema = 'your_database_name' AND table_name = 'your_table_name';- ストレステストを実行します。すべてのカラムに許容される最大文字数を入力したレコードを挿入し、実行時にクラッシュが発生しないことを確認します。## 学んだ教訓- データの正規化: 8KBの制限に達することは、多くの場合警告サインです。テーブルに100以上のカラムがある場合は、1:1の関係を使用して、より小さな関連テーブルに分割することを検討してください。- DYNAMIC への標準化: モダンなMySQL(5.7.9以降)はデフォルトで DYNAMIC になっています。古いサーバーから移行した場合、テーブルが COMPACT モードのままになっている可能性があります。- 型を正確に指定する: すべてのデフォルトとして VARCHAR(255) を使用するのはやめましょう。フィールドに20文字しか必要ない場合は、そのように定義して、内部のスキーマ計算を小さく保ちます。

Related Error Notes