そろそろMySQLのutf8について一言いっとくか

MySQLのutf8 charsetは、やれ「罠」だの「絵文字が入らなくて使えない」だの「utf8という名前はutf8mb4の別名にすべき」だの、散々な言われようでディスられてかわいそうな charset なんだけど、というか主に私がそう言ってる気もするんだけど、そろそろ utf8mb3 のエイリアスとしての utf8 は消え去ろうとしてるみたいなので、ここでちょっと勝手にフォローしておく。

UTF-8 エンコーディングの RFC は RFC3629で、ここで UTF-8 は最大4バイトと書かれている。 しかし、この RFC3629 の前のRFC2279では6バイトだった。 RFC3629 の日付は 2003/11 なので、つまり 2003/11 よりも前は UTF-8 の1文字のバイト数は最大6バイトだったのだ(少なくともRFC上では)。

MySQL が Unicode に対応したのはバージョン 4.1 からで、開発版4.1.0のリリースは 2003/04/03、正式版4.1.7のリリースは 2004/10/23 だった。すくなくとも開発版リリース時点では UTF-8 の理論的な最大長は6バイトだった。 理論的に最大6バイトと言っても、当時に実際にそんなに文字が割り当てられてるわけはなく、UTF-8対応しようとした時に6バイトに対応するのは無駄であるし、それよりも小さいバイト数に対応しようとするのは自然だと思う。

Unicode は当初2バイトにすべての文字を納めるという計画だったし、UTF-8は1文字が可変長なのでそのままではプログラムで扱いづらいため、内部的には2バイトの固定長で扱われることが多かった(たぶん今でも多いと思う)。 2バイトで表現できる範囲(U+0000〜U+FFFF)をUTF-8で表すと最大3バイトになる。UTF-8の最大バイト数を3バイトにするというのは当時は妥当な判断だったと思う。

たとえば Windows が UTF-8で4バイトになる文字(U+10000〜の文字)に対応したのは、2006年リリースの Windows Vista からだ。 Windows Vista が出るまでは世間で4バイトUTF-8文字なんて実質使えなかったのである。

utf8が最大3バイトなのは妥当だったとして、MySQL が4バイトUTF-8に対応したのは 5.5 (2010/12 リリース)で、Windows Vista の4年後なので、まあちょっと遅い気がしないでもない。

なお、utf8mb4 に対応した現在でも、テーブル名やカラム名には4バイト文字は使えない。絵文字テーブル名や絵文字カラム名を使いたかったみなさん、残念でした。

ところで、先般リリースされたMySQL 8.0 では utf8 を使用するととうとう warning が出るようになるまで地位が下がってきた。 将来 utf8 は utf8mb3 のエイリアスではなく utf8mb4 のエイリアスになるらしい。

mysql> create table t (hoge varchar(10)) charset utf8;
Query OK, 0 rows affected, 1 warning (0.22 sec)

Warning (Code 3719): 'utf8' is currently an alias for the character set UTF8MB3, 
which will be replaced by UTF8MB4 in a future release. Please consider using 
UTF8MB4 in order to be unambiguous.

ところが、utf8mb3 でテーブル作っても、show create table すると utf8 で出力しやがるんですよ。

mysql> show create table t\G
*************************** 1. row ***************************
       Table: t
Create Table: CREATE TABLE `t` (
  `hoge` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.02 sec)

なので、mysqldump してロードしてみると、

% sudo mysqldump -uroot test t > /tmp/dump.sql
% sudo mysql -uroot --show-warnings test < /tmp/dump.sql
Warning (Code 3719): 'utf8' is currently an alias for the character set UTF8MB3, 
which will be replaced by UTF8MB4 in a future release. Please consider using 
UTF8MB4 in order to be unambiguous.

ちょ、おま… ダンプしてロードするだけで warning て…。

まだ中途半端なようですな…。