Day4 前半のゴール
「“文字化けしない”だけじゃなく、“正しく比較・ソートできる”を意識する」
SQLite を使っていると、文字コードやソート順をあまり意識しないままでも、そこそこ動いてしまいます。
でも MySQL では、ここをちゃんと決めておかないと、
日本語が文字化けする
大文字・小文字の扱いが想定と違う
「あいうえお」の並び順がおかしい
といった地味に痛い問題が出てきます。
Day4 前半のゴールは、
utf8mb4 とは何か(なぜ utf8 ではなく utf8mb4 なのか)
collation(照合順序)とは何か(比較・ソートにどう効くのか)
を、「日本語アプリを作る前提」で腹落ちさせることです。
文字コードとは何か
「“文字をどう数値に変換するか”というルール」
まず、文字コードそのものを一度言葉にしておきます。
コンピュータは文字をそのまま扱えないので、
内部では「数値」に変換して扱います。
「A」を 65
「あ」を 12354
みたいに、「文字 ↔ 数値」の対応表を決めたものが文字コードです。
有名どころだと、
ASCII
Shift_JIS
UTF-8
などがあります。
SQLite では、内部的には UTF-8 や UTF-16 を使っていましたが、
あまり意識せずに済んでいたと思います。
MySQL では、
データベース全体の文字コード
テーブルごとの文字コード
カラムごとの文字コード
を指定できるので、
「最初に何を選ぶか」がとても重要になります。
utf8 と utf8mb4 の違い
「“MySQLのutf8”は“本物のUTF-8”ではない、という罠」
ここが MySQL 特有のややこしいポイントです。
名前が似ているのでややこしいのですが、
一般的な UTF-8
→ 最大4バイトで、ほぼすべての文字(絵文字なども含む)を表現できる
MySQL の utf8
→ 最大3バイトまでしか扱えない“擬似UTF-8”
という違いがあります。
つまり、MySQLで CHARACTER SET utf8 を使うと、
一部の文字(絵文字など)が保存できない
→ エラーになったり、文字化けしたりする
という問題が起きます。
これを解決するために用意されているのが、
utf8mb4
です。
これは「本物のUTF-8」に相当し、
4バイトまで使えるので、絵文字も含めてほぼ何でも保存できます。
なぜ utf8mb4 を選ぶべきなのか
「“とりあえずこれにしておけば困らない”標準設定」
結論から言うと、
新しく MySQL を使うなら、基本はすべて utf8mb4 にする
と覚えてしまってOKです。
理由はシンプルです。
日本語を含む多言語を安全に扱える
絵文字や特殊記号も保存できる
将来「この文字だけ入らない…」という事故を防げる
逆に、utf8 を選ぶメリットはほぼありません。
昔の互換性のために残っているだけ、くらいの認識で大丈夫です。
例:データベース作成時の指定
CREATE DATABASE app_db
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_general_ci;
SQLDay1 でも少し出しましたが、
「文字コードは utf8mb4 にする」が、現代の MySQL の“お約束”です。
collation(照合順序)とは何か
「“どう比較・ソートするか”のルールセット」
次に、collation(照合順序)です。
文字コードが「文字 ↔ 数値」の対応表だとすると、
collation は「その文字列をどう比較・ソートするか」のルールです。
例えば、こんなことを決めます。
大文字と小文字を区別するか
→ ‘A’ と ‘a’ を同じとみなすか、違うとみなすか
アクセント記号を区別するか
→ ‘é’ と ‘e’ を同じとみなすか、違うとみなすか
日本語のソート順をどうするか
→ ひらがな・カタカナ・漢字をどう並べるか
MySQL では、文字コードごとに複数の collation が用意されています。
utf8mb4_general_ciutf8mb4_unicode_ciutf8mb4_ja_0900_as_cs
など、名前に意味があります。
collation 名の読み方
「名前を分解すると“性格”が見えてくる」
例えば、utf8mb4_general_ci を分解してみます。
utf8mb4
→ 文字コード(UTF-8の4バイト版)
general
→ 一般的なルール(ざっくりした比較)
ci
→ case insensitive(大文字・小文字を区別しない)
同じように、utf8mb4_unicode_ci なら、
unicode
→ Unicodeのルールに沿った、より厳密な比較
ci
→ 大文字・小文字を区別しない
cs なら case sensitive(大文字・小文字を区別する)、ai なら accent insensitive(アクセントを区別しない)、as なら accent sensitive(アクセントを区別する)
といった具合です。
Day4 の段階では、
utf8mb4_general_ciutf8mb4_unicode_ci
この2つの名前と意味が分かれば十分です。
なぜ collation が重要なのか
「WHERE や ORDER BY の結果が“想定と違う”を防ぐ」
collation は、次のような場面に効いてきます。
文字列の比較(WHERE 句)
→ WHERE name = 'taro' で ‘Taro’ もヒットさせるかどうか
ソート(ORDER BY)
→ ORDER BY name で ‘A’ と ‘a’ の順番をどうするか
ユニーク制約
→ UNIQUE (email) で ‘USER@example.com’ と ‘user@example.com’ を同じとみなすか
例えば、utf8mb4_general_ci は「大文字・小文字を区別しない」ので、
WHERE email = 'USER@example.com'
で、'user@example.com' もヒットします。
これは「メールアドレスは大文字小文字を区別しない」という現実に合っています。
一方で、パスワードのように「絶対に区別したい」ものは、
そもそも平文で保存しないので、collation の話以前の問題です。
Day4 の段階では、
「collation は、文字列の比較・ソート・ユニーク制約に効くルール」
と押さえておけばOKです。
SQLite と MySQL の“文字まわり”の差分
「SQLiteは“あまり意識しなくてよかった”、MySQLは“最初に決める”」
SQLite では、
内部的にはUTF-8/UTF-16だが、あまり意識しなくても動く
大文字小文字の扱いも、そこまで細かく気にしないことが多い
という世界でした。
MySQL では、
文字コード(CHARACTER SET)を最初に決める
→ 基本は utf8mb4
照合順序(COLLATE)を最初に決める
→ 基本は utf8mb4_general_ci か utf8mb4_unicode_ci
という「最初の一手」がとても重要です。
ここを適当にすると、
後からテーブルごと変換する
アプリ側で無理やり合わせる
といった、面倒な作業が発生します。
Day4 前半のまとめ
文字コードは「文字 ↔ 数値」の対応表で、MySQLではデータベース・テーブル・カラムごとに指定できる。現代のMySQLでは、絵文字も含めて安全に扱える utf8mb4 を選ぶのが基本で、utf8 は3バイトまでしか扱えない“擬似UTF-8”なので新規では使わない。
collation(照合順序)は「文字列をどう比較・ソートするか」のルールセットで、大文字小文字を区別するか(ci/cs)、アクセントを区別するか(ai/as)、どの言語ルールに従うか(general/unicode/ja…)といった性格を持つ。utf8mb4_general_ci や utf8mb4_unicode_ci のように、文字コード+ルール+大文字小文字の扱いが名前に含まれており、特にメールアドレスや名前の比較・ソート・ユニーク制約に直接影響する。
SQLiteでは文字コードやソート順をあまり意識せずに済んでいたが、MySQLでは「最初に CHARACTER SET utf8mb4 と COLLATE をどうするか」を決めることが、後々の文字化け防止や正しい比較・ソートのために非常に重要になる。
後半では、
実際に utf8mb4+異なる collation でテーブルを作り、
大文字小文字や日本語のソート結果がどう変わるかを、
具体的なクエリで確認していきます。
