普段何気なく使っているMySQLでも、
気を付けないと意図しない挙動をしてしまうことがあります。
MySQLで照合順序を「utf8mb4_general_ci」で設定した場合、
「🍣と🍺」を同じ値であると認識してしまいます。
また、
照合順序を「utf8mb4_unicode_520_ci」で設定した場合、
「ハとバ」を同じ値であると認識してしまいます。
なぜこのような問題が発生するか1つ1つ解説していこうと思います。
前提知識
符号化文字集合と文字符号化方式
まず、コンピュータには、符号化文字集合というものがあります。
符号化文字集合とは、「どのような文字を扱うか」ということを定義したもので、
「a」や「あ」などの1つ1つの文字に対して、一意な番号を割り当てた対応表のことです。
例) ASCIIやJIS、Unicodeなど
ただ、
これだけではコンピュータで文字を表示することはできません。
符号化文字集合から、コンピュータが扱える数字(0,1の並び)に並び替える必要があります。
この「符号化文字集合から、コンピュータが扱える数字(0,1の並び)に変換」するための定義を文字符号化方式と言います。
一般的には、文字コードと言われているものです。
例) utf8やShift_JISなど
符号化文字集合には、各々の符号化方式があります。
具体的には、
符号化文字集合のUnicodeには、utf8やutf16といった文字符号化方式があります。
Unicode
Unicodeとは、
世界中で扱う文字を共通の文字集合として利用できるように考案・作成されたものです。
現在では、Unicodeを使用することがデファクトスタンダードになっています。
Unicodeは、
日常的に使う文字と日常的に使わない文字を別々に定義しています。
日常的に使う文字をBMP、日常的に使わない文字(絵文字など)をSMPと言います。
utf8mb4とは
MySQLにはutf8を指定する場合、utf8とutf8mb4があります。
この違いは何かというと、
UnicodeのSMPをサポートするかしないかに違いがあります。
utf8は、BMPのみをサポートしたものになるため、
SMP文字である絵文字を使用した場合、サポートされていないため、文字化けしてしまいます。
utf8mb4は、「SMP」もサポートした文字符号化方式となります。
そのため、
mysqlのutf8で絵文字を表示させたい場合は、utf8mb4を使用する必要があります。
🍣🍺問題
MySQLでutf8mb4を指定し、照合順序を特に指定しなかった場合、
utf8mb4_general_ciを照合順序として設定します。
ちなみに、照合順序とは、文字同士を比較やソートする際に使用されます。
この「utf8mb4_general_ci」が🍣🍺問題を引き起こします。
なぜそのようなことが起こってしまうかといいますと、
utf8mb4_general_ciはSMPに含まれる文字を同じ値として認識してしまうからです。
そのため、
意図してutf8mb4_general_ciを指定していない場合は、思わぬ挙動をしてしまいます。
ハハパパ問題
MySQLの照合順序をutf8mb4_general_ciではなく、
utf8mb4_unicode_520_ciを指定した場合、🍣🍺問題は解決しますが、今度はハハパパ問題が発生してしまいます。
これは、
MySQLの「ハ」と「パ」と「バ」を同じ文字として認識してしまう問題です。
原因としては、
標準規格として定められているソートのレベルがあるのですが、
utf8mb4_unicode_520_ciのソートレベルでは「ハ」と「パ」と「バ」を同じ文字として認識しまうものだからです。
対策
一体どの照合順序を選択すれば良いかといことになると思いますが、
現状上記に挙げた2つの問題を解決するには、utf8mb4_binを設定することになります。
以下が照合順序の表になります。
(同値と認識されるものは○。そうでないものは、×)
照合順序 | A = a | 🍣 = 🍺 | ハ = パ = バ |
utf8mb4_general_ci | ○ | ○ | × |
utf8mb4_unicode_ci | ○ | ○ | ○ |
utf8mb4_unicode_520_ci | ○ | × | ○ |
utf8mb4_bin | × | × | × |
まとめ
普段何気なく使用している文字でも、
コンピュータは様々なタイプがあり、
それを要件ごとに適切に設定していく必要があります。
特に、
照合順序は、比較やソートに関わってくるものなので、思わぬところで意図しない挙動が発生しますので、十分に注意する必要があります。
参考: