- 「utf8にしたのに文字化けした」の正体
- MySQLのutf8は3バイト
- utf8mb4とは何か
- なぜこんな仕様になったのか
- もっと危険な問題:気づかないまま壊れる
- インデックス長制限との関係
- 接続文字コードの罠
- 移行時に起きるトラブル
- どう対応すべきか
- まとめ
「utf8にしたのに文字化けした」の正体
MySQLのトラブルで非常に多いのが、文字コードに関する問題です。
テーブルもutf8、接続もutf8、設定ファイルもutf8。それでも保存時にエラーが出たり、文字化けが発生します。
典型的なログです。
Incorrect string value
多くの場合、ここでアプリケーションのエンコードやフレームワークを疑います。
しかし原因の大半はMySQLの仕様です。
結論から言うと、**MySQLのutf8はUTF-8ではありません。**
MySQLのutf8は3バイト
一般にUTF-8は1〜4バイトの可変長文字コードです。
しかしMySQLのutf8は最大3バイトです。
つまり、Unicodeの一部しか保存できません。
保存できる文字の例です。
- 日本語
- 英数字
- 一般的な記号
保存できない文字の代表例です。
- 絵文字
- 一部の拡張漢字
- 一部の記号
例えば次の文字です。
🙂
これをutf8カラムへINSERTするとエラーになります。
INSERT INTO messages (body) VALUES ('🙂');
アプリケーションが正しくても失敗します。
理由は4バイト文字だからです。
utf8mb4とは何か
utf8mb4は、MySQLが後から追加した文字コードです。
こちらが本当のUTF-8に相当します。
違いは単純です。
utf8
- 最大3バイト
utf8mb4
- 最大4バイト
この1バイト差が大きな問題を生みます。
なぜこんな仕様になったのか
初期のMySQLが作られた時代、Unicodeの4バイト領域はほとんど使われていませんでした。
主な用途は欧文と日本語です。
当時は次の要求が重要でした。
- ディスク容量を減らす
- インデックスを小さくする
- メモリ使用量を抑える
そのため3バイトUTF-8が採用されました。
後にUnicodeが拡張され、絵文字が普及して問題が表面化しました。
つまりバグではなく歴史的事情です。
もっと危険な問題:気づかないまま壊れる
怖いのは、必ずしもエラーにならないことです。
環境によっては、次の現象が起きます。
- 文字が「?」になる
- 切り詰められる
- 保存は成功するが内容が変わる
エラーが出ないため、気づくのが遅れます。
特に問い合わせ対応で発覚します。
インデックス長制限との関係
utf8mb4へ変更すると、次のエラーが出ることがあります。
Specified key was too long
理由はインデックス長です。
utf8mb4は4バイトなので、同じVARCHARでもサイズが増えます。
例えばです。
VARCHAR(255)
utf8
255 × 3 = 765バイト
utf8mb4
255 × 4 = 1020バイト
古いInnoDBではインデックス上限を超えます。
そのため次の対応が必要になります。
- VARCHAR長を191へ変更
- InnoDB設定変更
- MySQLバージョン更新
単なる文字コード変更では終わりません。
接続文字コードの罠
もう一つの典型的な問題が接続設定です。
テーブルがutf8mb4でも、接続がutf8だと壊れます。
例えばアプリの接続設定です。
SET NAMES utf8;
この時点で4バイト文字は失われます。
テーブル側の設定だけでは不十分です。
確認すべき項目です。
- server character set
- database character set
- table character set
- connection character set
すべて揃って初めて正常動作します。
移行時に起きるトラブル
utf8からutf8mb4への移行では次の問題が起きます。
- インデックス作成失敗
- UNIQUE制約エラー
- ソート順変化
- LIKE検索結果変化
特に照合順序(collation)が影響します。
文字比較の結果が変わるため、検索結果が変化することがあります。
どう対応すべきか
単にALTER TABLEするだけでは不十分です。
次の順序で進めます。
- DB設定変更
- テーブル変更
- カラム変更
- 接続設定変更
- アプリ検証
途中を省略すると、部分的に文字化けが残ります。
まとめ
MySQLのutf8問題は設定ミスではありません。
仕様の誤解です。
utf8という名前から、本物のUTF-8だと認識してしまいます。
しかし実際は互換形式です。
現在、文字コードはインフラではなくアプリケーションの仕様の一部です。
そのため、後からの変更は影響が大きくなります。
文字化けトラブルの多くはバグではありません。
「どのUTF-8を使っているか」を確認していなかった結果です。
そして対策は単純です。
新規システムでは最初からutf8mb4を選択することです。