この前 MySQL Casual に登壇して、「MySQLの文字コード事情」と称して発表してきました。
終電の都合で途中退席しましたが楽しかったです。また機会があれば参加したいです。
発表スライドはこちら
www.slideshare.net
以下、補足のような何か。
「Charset≒エンコーディング (MySQLに限らない)」
英語版のWikipediaでもcharsetは Character encoding にリダイレクトされます。
自分がcharsetという用語に出会ったのはおそらくメールのContent-Typeヘッダが初めてだったと思います。 今ではメールだけではなくHTTPのヘッダでも使用されています。
なお、CharsetはInternet Assigned Numbers Authority(IANA)という組織で管理されています。http://www.iana.org/assignments/character-sets/character-sets.xhtml
ujis
MySQLで日本語を使用できるようになった時にEUC-JPエンコーディングのcharsetの名前をujisとしてしまったのは自分です。ゴメンナサイ。
いや、今でこそEUC-JPの方がメジャーでujisなんてもう見かけないんですけど、1998年当時はeucJPとujisのどちらも使われたんですよ。(あと ujis と sjis で韻を踏んでいていいかなーとか…)
EUCは Extended Unix Code の略で、ujisは Unixized JIS の略です。ググってみたら ujis の方が EUC-JP よりも歴史は古いようですね。
「歴史的には、まず「日本語EUC」の元 (ujis) があって、その工夫を I18N 的枠組に拡張したものが EUC」
http://naruse.hateblo.jp/entry/20090308/1236517235
「ふつうはutf8mb4」
とスライドには書きましたが、cp932を使うメリットも無いことはないです。
UTF-8は日本語の文字は普通3バイトですがCP932は2バイトです。 つまりディスクやメモリの消費量がUTF-8に比べて2/3で済むということです。
扱える文字が Windows-31J の範囲の文字だけで良くて、少しでも資源を節約したいのであれば、cp932を使用するのもいいかもしれません。
🍣=🍺問題とCollation
伝統的にMySQLは標準で大文字小文字を区別しないので、ci(Case Insensitive)を使いたくなってしまうのですけど、PostgreSQL とかは普通に大文字小文字は別の文字扱いだし、実は MySQL も utf8mb4_bin でも全然問題ないのかもしれません。
utf8mb4_bin であれば🍣=🍺問題も、ハハ=パパ問題も発生しませんし。
‘🍣’=‘🍺’=‘�’
MySQLで同じ文字とみなされるかどうかは WEIGHT_STRING() という関数の戻り値が同じかどうかで確かめられます。
SET NAMES utf8mb4 COLLATE utf8mb4_general_ci; SELECT HEX(WEIGHT_STRING('🍣')); -- => FFFD SELECT HEX(WEIGHT_STRING('🍺')); -- => FFFD SELECT HEX(WEIGHT_STRING('�')); -- => FFFD SET NAMES utf8mb4 COLLATE utf8mb4_unicode_520_ci; SELECT HEX(WEIGHT_STRING('🍣')); -- => FBC3F363 SELECT HEX(WEIGHT_STRING('🍺')); -- => FBC3F37A SET NAMES utf8mb4 COLLATE utf8mb4_bin; SELECT HEX(WEIGHT_STRING('🍣')); -- => 01F363 SELECT HEX(WEIGHT_STRING('🍺')); -- => 01F37A
utf8mb4_bin の場合は Unicode のコードポイントがそのまま使用されるようです。
「'パ'=‘パ'」と「'パ’ LIKE ‘パ'」
半角カナの「パ」は「ハ」と「゚」の二文字で構成されていますが、unicode_ci では一文字の「パ」と一致します。
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci; SELECT 'パ'='パ'; -- => 1
ですが、LIKE では一致しません。
SELECT 'パ' LIKE 'パ'; -- => 0
SQL 標準では、LIKE は文字ごとに一致を実行するため、= 比較演算子とは異なる結果が生成される可能性があります。
https://dev.mysql.com/doc/refman/5.6/ja/string-comparison-functions.html#operator_like
…ということのようです。
Unicode Collation Algorithm
そのうち書きたい(書くとは言ってない)。