MySQL の文字コードと照合順序

MySQL で文字列データを正しく扱うには、文字コード(キャラクタセット)と照合順序(コレーション)の設定が欠かせません。文字化けや予期しないソート結果の多くは、この設定の不備が原因です。

文字コードとは

文字コードは、文字をどのバイト列で表現するかを定義するルールです。MySQL では「キャラクタセット(CHARACTER SET / CHARSET)」と呼びます。

utf8mb4

UTF-8 の完全な実装で、絵文字を含むすべての Unicode 文字を格納できます。MySQL 8.0 ではデフォルトのキャラクタセットです。1文字あたり最大4バイトを使用します。

utf8(utf8mb3)

MySQL 独自の UTF-8 実装で、1文字あたり最大3バイトまでしか扱えません。4バイト文字(絵文字、一部の漢字)を格納できないため、新規プロジェクトでは使用すべきではありません。

MySQL の utf8 は厳密には UTF-8 ではないという歴史的な事情があります。MySQL 8.0 で utf8mb4 がデフォルトになったことで、この混乱は解消されつつありますが、古いシステムでは依然として utf8(utf8mb3)が使われていることがあります。

照合順序とは

照合順序は、文字列の比較やソートの方法を定義するルールです。同じキャラクタセットでも、照合順序によって「AとaがAが等しいか」「はとハは等しいか」が変わります。

-- 照合順序の確認
SHOW VARIABLES LIKE 'collation%';

-- テーブルの照合順序を指定
CREATE TABLE messages (
  id INT AUTO_INCREMENT PRIMARY KEY,
  content VARCHAR(500) NOT NULL
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

主要な照合順序の違い

照合順序特徴用途
utf8mb4_general_ci高速だが比較精度が低いレガシーシステム
utf8mb4_unicode_ciUnicode 標準の比較一般的な用途
utf8mb4_0900_ai_ciMySQL 8.0 デフォルト新規プロジェクト推奨

名前の末尾にある ci は Case Insensitive(大文字小文字を区別しない)、ai は Accent Insensitive(アクセント記号を区別しない)を意味します。

ci(大文字小文字を区別しない)

‘Alice’ = ‘alice’ が TRUE になる。ユーザー名やメールアドレスの検索には便利だが、パスワードハッシュのようなバイナリ比較が必要な場面では不適切。

cs / bin(大文字小文字を区別する)

‘Alice’ ≠ ‘alice’ となる。厳密な一致が必要なカラムに使う。BINARY 属性を付けるか、_bin 照合順序を指定する。

設定の4つのレベル

文字コードと照合順序は、サーバー → データベース → テーブル → カラムの4段階で設定でき、下位の設定が上位を上書きします。

-- データベースレベル
CREATE DATABASE myapp 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_0900_ai_ci;

-- テーブルレベル(データベースの設定を継承)
CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  -- カラムレベルで個別に指定も可能
  code VARCHAR(20) NOT NULL COLLATE utf8mb4_bin
);

基本的にはデータベースレベルで utf8mb4 と utf8mb4_0900_ai_ci(MySQL 8.0 の場合)を設定し、厳密な比較が必要なカラムだけ個別に _bin を指定するのがシンプルな運用方針です。

文字コード関連のトラブル

文字化けが起きる場合は、クライアント接続の文字コード設定が原因であることが多いです。テーブルが utf8mb4 でも、接続が latin1 だと文字化けします。接続時に SET NAMES utf8mb4 を実行するか、アプリケーションの接続文字列で charset=utf8mb4 を指定して、すべての経路で文字コードを統一することが重要です。