こんにちは、新卒2年目のバックエンドエンジニアの伊藤です。
みなさんは、テーブル作成の際にCHARACTER SET(charset)
を意識していますか?
環境によっては、デフォルトで設定されていることもあり、意識しない人もいると思います。
ただ、このcharsetの設定を間違えると、特定の文字が使えない
や絵文字が使えない
などといった問題が発生してしまいます。
タイトルにもある、MySQL
では使用できるcharsetを下記のコマンドで確認することができます。
-- MySQL version8.1.0 SHOW CHARACTER SET; +----------+---------------------------------+---------------------+--------+ | Charset | Description | Default collation | Maxlen | +----------+---------------------------------+---------------------+--------+ | armscii8 | ARMSCII-8 Armenian | armscii8_general_ci | 1 | | ascii | US ASCII | ascii_general_ci | 1 | | big5 | Big5 Traditional Chinese | big5_chinese_ci | 2 | | binary | Binary pseudo charset | binary | 1 | | cp1250 | Windows Central European | cp1250_general_ci | 1 | | cp1251 | Windows Cyrillic | cp1251_general_ci | 1 | | cp1256 | Windows Arabic | cp1256_general_ci | 1 | | cp1257 | Windows Baltic | cp1257_general_ci | 1 | | cp850 | DOS West European | cp850_general_ci | 1 | | cp852 | DOS Central European | cp852_general_ci | 1 | | cp866 | DOS Russian | cp866_general_ci | 1 | | cp932 | SJIS for Windows Japanese | cp932_japanese_ci | 2 | | dec8 | DEC West European | dec8_swedish_ci | 1 | | eucjpms | UJIS for Windows Japanese | eucjpms_japanese_ci | 3 | | euckr | EUC-KR Korean | euckr_korean_ci | 2 | | gb18030 | China National Standard GB18030 | gb18030_chinese_ci | 4 | | gb2312 | GB2312 Simplified Chinese | gb2312_chinese_ci | 2 | | gbk | GBK Simplified Chinese | gbk_chinese_ci | 2 | | geostd8 | GEOSTD8 Georgian | geostd8_general_ci | 1 | | greek | ISO 8859-7 Greek | greek_general_ci | 1 | | hebrew | ISO 8859-8 Hebrew | hebrew_general_ci | 1 | | hp8 | HP West European | hp8_english_ci | 1 | | keybcs2 | DOS Kamenicky Czech-Slovak | keybcs2_general_ci | 1 | | koi8r | KOI8-R Relcom Russian | koi8r_general_ci | 1 | | koi8u | KOI8-U Ukrainian | koi8u_general_ci | 1 | | latin1 | cp1252 West European | latin1_swedish_ci | 1 | | latin2 | ISO 8859-2 Central European | latin2_general_ci | 1 | | latin5 | ISO 8859-9 Turkish | latin5_turkish_ci | 1 | | latin7 | ISO 8859-13 Baltic | latin7_general_ci | 1 | | macce | Mac Central European | macce_general_ci | 1 | | macroman | Mac West European | macroman_general_ci | 1 | | sjis | Shift-JIS Japanese | sjis_japanese_ci | 2 | | swe7 | 7bit Swedish | swe7_swedish_ci | 1 | | tis620 | TIS620 Thai | tis620_thai_ci | 1 | | ucs2 | UCS-2 Unicode | ucs2_general_ci | 2 | | ujis | EUC-JP Japanese | ujis_japanese_ci | 3 | | utf16 | UTF-16 Unicode | utf16_general_ci | 4 | | utf16le | UTF-16LE Unicode | utf16le_general_ci | 4 | | utf32 | UTF-32 Unicode | utf32_general_ci | 4 | | utf8mb3 | UTF-8 Unicode | utf8mb3_general_ci | 3 | | utf8mb4 | UTF-8 Unicode | utf8mb4_0900_ai_ci | 4 | +----------+---------------------------------+---------------------+--------+ 41 rows in set (0.02 sec)
41種類もあるcharset
を全て解説はできないので、
今回の記事ではutf8mb3
とutf8mb4
について話していきます。
理由としては、ラボルでは業務でUTF-8
を使用する機会が多いからです。
utf8mb3
とutf8mb4
の違い
保存できる文字
utf8mb3
とutf8mb4
では保存できる文字が違います。
実際にテーブルを作成して、確認してみましょう。
環境はMySQL version8.1.0
です。
-- テストテーブルの作成 CREATE TABLE `test_charset` ( `utf8mb3_column` VARCHAR(32) CHARACTER SET utf8mb3, `utf8mb4_column` VARCHAR(32) CHARACTER SET utf8mb4 ); -- utf8mb3 INSERT INTO test_charset (`utf8mb3_column`) VALUES ('𠮷'); -- 結果 Query 1 ERROR : Incorrect string value: '\xF0\xA0\xAE\xB7' for column 'utf8mb3_column' at row 1 -- utf8mb4 INSERT INTO test_charset (`utf8mb4_column`) VALUES ('𠮷'); --- 結果 Query 1 OK: 1 row affected
このように、
utf8mb3
では1文字で4バイトを超えるような文字(🍣や🍺、𠮷
など)が保存できません。
また、公式からも非推奨と言われており、utf8mb4
が推奨されています。
公式ドキュメント(下部の参考を参照)より引用
utf8mb3 文字セットは非推奨であり、将来の MySQL リリースで削除される予定です。
where句で使える文字
4バイトを超えるような文字を保存できない
と言いましたが、実はwhere句で使用することもできません。
-- 上で作成したテーブルを使用 SELECT * FROM test_charset WHERE utf8mb3_column = "𠮷"; -- 出力されるメッセージ Query 1 : Illegal mix of collations (utf8mb3_general_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,COERCIBLE) for operation '=' SELECT * FROM test_charset WHERE utf8mb4_column = "𠮷"; -- 出力されるメッセージ Query 1 OK
このように、utf8mb3
は4バイトの文字をwhere句で指定するとエラーになりますが、
実装者がこのような操作をすることはないと思います。
しかし、toC
のサービスのような自由入力フォームやsqlについてあまり強くない人の操作など、
このようなエラーが発生する機会は0ではないので、頭の片隅に入れておきましょう。
utf8 というエイリアス
MySQLにはutf8
というcahrsetがありますが、これはどちらのcharsetが使われると思いますか?
実際に作成して確認していきます。
-- テーブル作成 CREATE TABLE `test_charset_part2` ( `utf8_column` VARCHAR(32) CHARACTER SET utf8, `utf8mb3_column` VARCHAR(32) CHARACTER SET utf8mb3, `utf8mb4_column` VARCHAR(32) CHARACTER SET utf8mb4 ); -- 文字コード確認 SHOW CREATE TABLE `test_charset_part2`; -- 結果 CREATE TABLE `test_charset_part2` ( `utf8_column` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, `utf8mb3_column` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, `utf8mb4_column` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
このエイリアスは、非推奨であるutf8mb3
が使われるため使用する際は気をつけてください。
ただ、公式では、いずれはutf8mb4
のエイリアスに移行すると言っており、使用も非推奨になっています。
公式ドキュメント(下部の参考)より引用
utf8 は現在 utf8mb3 のエイリアスですが、ある時点では utf8 が utf8mb4 への参照になることが予想されます。 utf8 の意味があいまいにならないように、utf8 ではなく文字セット参照に utf8mb4 を明示的に指定することを検討してください。
まとめ
utf8mb3
は常用漢字を含む日本語には対応しているため、意識せず使用している箇所があるかもしれません。(絵文字などのバリデーションしなくてすみますし)
ただ、公式では非推奨であり、将来的に削除予定とも言われています。
そのため、今後作成するテーブルについてはutf8mb3
やutf8
は使用しないようにし、
charsetを意識してテーブルを作成していきましょう。
最後に
ラボルでは、エンジニアを積極採用中です。1、2年目のエンジニアから経験豊富なテックリードやエンジニリングマネージャーまで、興味がある方はぜひご応募ください!!
参考
MySQL 8.0 リファレンスマニュアル / utf8mb3 文字セット https://dev.mysql.com/doc/refman/8.0/ja/charset-unicode-utf8mb3.html