RailsとMySQLの文字コードの話


前提

Rails5系 (以下、「Rails」はRails5系を指す)
MySQL5系 (以下、「MySQL」はMySQL5系を指す)

概要

RailsのActiveRecordは多様なDB操作を簡略化してくれる。
データベース作成もdb:createコマンド一発だが、文字コードと照合順序をちゃんと確認しないとちょっと困るかもしれない。
というか困った。

何も考えずにdb:createすると絵文字の使えない旧時代のWebアプリになる。

文字コード

CHARACTER SET UTF8

RailsでMySQLにdb:createすると、デフォルトではCHARACTER SET utf8でテーブルが作られる。

mysql> show variables like "character_set_database";
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| character_set_database | utf8  |
+------------------------+-------+
1 row in set (0.00 sec)

が、MySQLのutf84バイト文字が扱えない
JIS第三・第四水準漢字の多くとemojiは4バイトに該当するそうだ。
4バイト文字を扱えるのはutf8mb4という別設定となる。

英語圏ではあまり問題視されていなかったのだろうが、漢字を使う場合なんかはちょっと困るので、CHARACTER SET utf8mb4推奨。
MySQL側のデフォルトはどこかのバージョンでutf8mb4になったそうだが、Railsで作る場合はRailsの設定次第なのが困りどころ。

Railsではdatabase.ymlで変更できます。
ついでに照合順序(後述)もここで変更可。

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  charset: utf8mb4
  collation: utf8mb4_general_ci

emojiは4バイト

この頃は英語圏でもemojiの普及に従って4バイト文字に「ちゃんと」対応する流れがあるらしい。
emojiは4バイトなので、今までkanjiから目を反らし続けてきた数多のデータベース管理者が頭を悩ませたと思われる。

照合順序

照合順序は、MySQLのデフォルトがCOLLATE utf8mb4_general_ciで、
Railsのdb:createのデフォルトはCOLLATE utf8mb4_unicode_ciらしい。

検索時に何を同値扱いにするかに違いがあり、スピードはgeneral_ciの方が少し上らしい
これが結構違うので、色々な文字を検索したい場合は要考慮。

照合順序で何が変わるか

いわゆる「曖昧さ」に影響があり、照合順序によって検索結果に類似文字を含めたり含めなかったりできる。何が「類似」とされるかも違う。
以下のように油断すると困ることもある。

ハハパパ

utf8mb4_unicode_ciは「ハハ」と「パパ」が同値扱いになる。

寿司ビール

utf8mb4_general_ciは絵文字対応に問題があり、例えばが同値扱い。
寿司ビールはutf8mb4_unicode_ciでも発生するが、新し目のutf8mb4_unicode_520_ciでは発生しない(ただしハハパパは発生)。

MySQL5照合順序紹介

utf8mb4_unicode_ci => ハハパパ、寿司ビール
utf8mb4_unicode_520_ci => ハハパパ
utf8mb4_general_ci => 寿司ビール
utf8mb4_bin => 全て区別

その他「Aa」とか「アァ」とか細かい違いについては先人のまとめを見て下さい。
参考リンク:https://qiita.com/tfunato/items/e48ad0a37b8244a788f6

PostgreSQLでは

ハハパパも寿司ビールも起きないらしい。

MySQL8では

MySQL8.0.1にはutf8mb4_ja_0900_as_csが追加され、これはハハパパ寿司ビール両方に対応しているらしい。
参考リンク:https://yoku0825.blogspot.com/2017/04/mysql-801utf8mb4ja0900ascs.html

まとめ

データベースの文字コードと照合順序の確認は早めにしよう。