はじめに
MySQLで「ひらがなの『あ』があるのに、カタカナの『ア』を登録しようとしたら
重複エラー(Unique制約違反)が出る」という現象に直面しました。
調査の結果、文字コードと**照合順序(Collation)**の設定が原因であることが分かりました。
本記事ではその原因と対策、そして注意点についてまとめます。
1. 発生していた問題と原因
◼︎現象
テーブルに UNIQUE 制約を張っているカラムにおいて、以下の文字が「同じ」と判定され、重複登録ができない。
ひらがな vs カタカナ(例:あ と ア)
大文字 vs 小文字(例:A と a)
◼︎原因
文字コードが utf8(古い仕様)、かつ照合順序が utf8_unicode_ci であったためです。 末尾の _ci (Case Insensitive) は「大文字小文字(および全角半角やカナなど)を区別しない」というルールであり、MySQLがこれらを同一視して重複と判定していました。
2. 実施した対策
以下の2点を変更しました。
① 文字コードを utf8 → utf8mb4 に変更
理由: utf8 (MySQL独自仕様) は最大3バイト。絵文字などの4バイト文字を保存しようとするとエラーや文字化けが発生するため。
メリット: 🍣や🐈などの絵文字も安全に扱えるようになります。
② 照合順序を utf8mb4_bin に変更
理由: _bin (Binary) は文字をバイナリ値(0/1)で比較するため、非常に厳格。
メリット: 「あ」と「ア」を完全に別物として扱い、重複登録を回避できます。
-- 修正用SQL例
ALTER TABLE `log_project_actions`
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
3. 「すべてのカラムを _bin にして大丈夫か?」という懸念
「一括で utf8mb4_bin に変えてしまったが、弊害はないか?」という点について検討します。
◼︎メリット
認証の厳格化: ユーザーIDやパスワード、トークンの比較がバイナリレベルで正確になります。
重複の解消: 今回の目的通り、カナや大文字小文字の差異を許容できます。
◼︎注意点・デメリット
① メールアドレスによるログインへの影響
_bin にすると、User@example.com と user@example.com を別人と判定します。
② 日本語のソート(並び替え)順
_bin は五十音順ではなく「バイナリ順(文字コード順)」で並べます。
現象: あ の次に ア が来るとは限らず、一覧画面などでユーザーが違和感を感じる可能性があります。
対策: 自然なソートが必要な場合は、ORDER BY 句で一時的に Collation を指定します。
SQL
-- 表示時だけ日本語の順序にする
SELECT * FROM users ORDER BY name COLLATE utf8mb4_ja_0900_as_cs;
4. 本番環境での実行時の注意(ハマりポイント)
既存の巨大なテーブルを ALTER する際は以下の点に注意が必要です。
インデックスサイズの上限エラー: utf8 → utf8mb4 になると1文字の最大バイト数が増えるため、既存のインデックス長(767バイト制限)に引っかかることがあります。
対策: ROW_FORMAT=DYNAMIC を指定して実行しましょう。
外部キー制約: 外部キーがある場合、変換に失敗することがあります。一時的に SET FOREIGN_KEY_CHECKS=0; を活用します。
ダウンタイム: CONVERT TO はテーブルのコピーを作成するため、データ量に比例して時間がかかります。必ずメンテナンス時間を確保して実行しましょう。
まとめ
「あ」と「ア」を区別したいなら _bin。
絵文字に対応したいなら utf8mb4。
すべて _bin にした場合、「メールアドレス認証」と「日本語ソート順」の挙動に注意が必要。