#寿司ビール問題
##はじめに
今回ご紹介するのは寿司ビール問題についてです。
##寿司ビール問題とは
二つの絵文字、これが同じ文字扱いされてしまうこと。
つまり
🍣=🍺
別に他の絵文字でも同じです。
🐶=🐱
このように文字コードが原因でMySQLにて絵文字が同じ文字列扱いを受ける問題を寿司ビール問題と言います。(なんで寿司とビールになったかは不明)
##そもそも文字コードってなんだっけ
「とりあえずutf-8使えばいんじゃね?」
って考えてました。でもそのとりあえず
を払拭しなければ中級者にはなれないと思い、一度文字コードを振りかえってみる。
文字コード、調べていたら混乱したのでここではっきりさせておく。
まず文字コードとは文字集合、文字符号化方式の二つの要素のことを指す。(誰だこんな混乱するような言い回し作ったの)
文字集合
用いる文字の集合のこと、またその文字の対応する識別子のこと。Unicode,JIS X 0213などのこと。
文字符号化方式
上記の文字集合で得た識別子を符号化するときに用いる方式のこと。つまりエンコード。
こちらの記事がわかりやすいかも
んで、今回、🍣と🍺が同じ扱いを受ける原因なのはcharsetのutf8。
あ?charset?
またごちゃごちゃしそうですが、charsetとは「文字集合」と「エンコード」の両方を含んだ意味あいです。
MySQLのcharsetをutf8にすると、その場合Unicodeによって対応づけられた🍣と🍺の識別子を符号化して保存しようとすると、1文字1~3バイトしか対応しておらず、4バイト文字である絵文字は上手く保存できず文字化けして結局同じ文字扱いになってしまうのである。
##対応
まずはcharsetをutf8mb4
にする。
utf8mb4
は1~4バイトなので絵文字もOK。MySQLのcharsetをutf8mb4
にすればいいわけだが、ここで注意するのが、MySQLでは、サーバー、クライアント、サーバー/クライアント間、データベースごと、テーブルごと、カラムごとに指定できる。もちろん全て統一した方が良い。
次にcollationの設定です。
collationとはどの文字とどの文字を同値と扱うかという設定で、例えば大文字小文字は区別するのか、
以下のようになっている。
collation | A:a | 🍣:🍺 | は:ば、ぱ:ハ | や:ゃ |
---|---|---|---|---|
general_ci | = | = | ≠ | ≠ |
bin | ≠ | ≠ | ≠ | ≠ |
unicode_ci | = | = | = | = |
unicode_520_ci | = | ≠ | = | = |
...理想的なのがない...(MySQL8では日本語に対応したcollationがあるがそれも微妙)
結局ここでトレードオフ的な感じになってしまう。
##まとめ
そもそも絵文字を同値と扱わないで欲しいケースってなんなのだろう。気になる。
実は今回実装して試したかったのですが、RailsのDBをMySQLに移行しようとしたらハマってしまい。結局できませんでした...時間がないのでとりあえず概論的な感じです。明日までにできたら試してみます。
今回の内容はこちらのスライドがおすすめです。
→https://www.slideshare.net/tmtm/mysql-2017-76154739?ref=http://tmtms.hatenablog.com/entry/2017/05/21/myna_nagano
##参考にしたの
MySQLのencodingをutf8からutfmb4に変更して寿司ビール問題に対応する
https://techracho.bpsinc.jp/hachi8833/2016_08_25/25044#mysqlutf8mb4
[MySQL] 文字コード問題 -みんな大好き寿司ビール🍣🍺-
https://qiita.com/mamy1326/items/f516a3b7819a6a788dc3
ActiveRecordでデフォルトの照合順序を変更する
https://qiita.com/kamipo/items/d7863f0df24916005657