MySQLではcharacter set
charsetやcollationとはなにかについては説明はしません。よって、
charsetやcollationの各レベルの設定方法
グローバル
以下のシステム変数を設定します。
character_
… サーバーのデフォルトのcharsetset_ server collation_
… サーバーのデフォルトのcollationserver
データベース
CREATE DATABASE
文に指定することができます。
CREATE DATABASE `test` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
上記例は、test
データベースのcharsetにutf8mb4
、utf8mb4_
を設定しています。
テーブルとカラム
CREATE TABLE
文に指定します。
CREATE TABLE tbl1 ( id bigint NOT NULL, col1 varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_ci NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
上記例は、tbl1
テーブルのcharsetにutf8
、utf8_
を設定しています。またtbl1.
カラムのcharsetにutf8mb4
、utf8mb4_
を設定しています。
MySQLのデフォルトcollationの注意点
では、
CREATE DATABASE
やCREATE TABLE
文ではDEFAULT CHARSET=xx COLLATE=xx
の部分を省略することもできます。CREATE TABLE
文を例に、
前提として、
- グローバルレベルのcharset… utf8mb4
- グローバルレベルのcollation…
utf8mb4_
bin
mysql> show global variables like 'collation_server'; +------------------+-------------+ | Variable_name | Value | +------------------+-------------+ | collation_server | utf8mb4_bin | +------------------+-------------+
- データベースレベルのcharset… utf8mb4
- データベースレベルのcollation…
utf8mb4_
unicode_ ci
mysql> CREATE DATABASE `db` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 1 row in set (0.00 sec)
db
データベース内に以下の3つタイプのCREATE TABLEを実行すると、
CREATE TABLE t1 (col1 varchar(10));
CREATE TABLE t2 (col1 varchar(10)) DEFAULT CHARSET=utf8mb4;
CREATE TABLE t3 (col1 varchar(10)) DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_
general_ ci;
結果は以下の通りです。
Table | collation |
---|---|
t1 | utf8mb4_ |
t2 | utf8mb4_ |
t3 | utf8mb4_ |
t1については、utf8mb4_
という、
つまり、DEFAULT CHARSET=utf8mb4
のみ記述すると、collation_
システム変数に設定されているサーバーのデフォルトcollationでもデータベースレベルのcollationでもない、DEFAULT CHARSET=xx COLLATE=xx
を省略せずに記述するのが良いでしょう。
また、SHOW COLLATION
文を実行します。Default
カラムがYesになっているものが、
ちなみに、CREATE DATABASE
文についても同様の動きをします。DEFAULT CHARACTER SET xx COLLATE xx
を省略すると、
CREATE DATABASE db1 ;
CREATE DATABASE db2 DEFAULT CHARACTER SET utf8mb4;
CREATE DATABASE db3 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_
general_ ci;
結果は以下の通りです。
Database | collation |
---|---|
db1 | utf8mb4_ |
db2 | utf8mb4_ |
db3 | utf8mb4_ |
MySQL 8.0アップグレード時の注意点
前述のデフォルトcollationはMySQL 8.utf8mb4_
であり、utf8mb4_
に変更されました。
MySQL 5.utf8mb4_
で運用されているMySQL 5.
# mysqldump --no-data test57db test_account -p -- MySQL dump 10.13 Distrib 5.7.22, for linux-glibc2.12 (x86_64) <snip> CREATE TABLE `test_account` ( `user_id` bigint(20) NOT NULL, `created_at` int(10) unsigned NOT NULL, `updated_at` int(10) unsigned NOT NULL, PRIMARY KEY (`user_id`), ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; <snip> -- Dump completed on 2021-10-07 22:18:18
DEFAULT CHARSET=utf8mb4
のみの記述で出力されてしまいます。このdumpファイルをそのままMySQL8.utf8mb4_
ではなくutf8mb4_
が設定されてしまいます。
この問題を解決するためには、default_
システム変数を使用します。このシステム変数はutf8mb4におけるMySQLのデフォルトcollationを指定します。デフォルトはutf8mb4_
です。これをutf8mb4_
に変更します。
mysql> SET GLOBAL default_collation_for_utf8mb4=utf8mb4_general_ci;
この変更をすると、DEFAULT CHARSET=utf8mb4
のみの記述のCREATE TABLE文であっても、utf8mb4_
でテーブルが作成されます。
default_
システム変数の注意点として、SET PERSIST
を使って設定します。詳しくは第94回 SET PERSISTを使ってシステム変数を永続化させるをご参照ください。また、
テーブル間でcollationが異なるときの問題
テーブル間でcollationが異なるときに起こる問題について紹介したいと思います。その場合、
たとえば、
CREATE TABLE `t1` ( `id` int NOT NULL, `col1` varchar(10) COLLATE utf8mb4_bin DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; CREATE TABLE `t2` ( `id` int NOT NULL, `col1` varchar(10) COLLATE utf8mb4_general_ci DEFAULT NULL, PRIMARY KEY (`id`), KEY(col1) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; INSERT INTO t1 VALUES (1,'a'),(2,'b'),(3,'b'); INSERT INTO t2 VALUES (1,'a'),(2,'b'),(3,'b');
t1.
がutf8mb4_
でt2.
がutf8mb4_
とします。このときに駆動表にt1
をt2
のcol1
と結合するクエリを実行してみます。
mysql> explain SELECT * FROM t1 JOIN t2 ON t1.col1=t2.col1; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------------------------+ | 1 | SIMPLE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100.00 | NULL | | 1 | SIMPLE | t2 | NULL | ALL | col1 | NULL | NULL | NULL | 3 | 33.33 | Range checked for each record (index map: 0x2) | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+------------------------------------------------+
本来であれば、t2.
のインデックスを効かせて解決できるはずですが、
Tipsとして、t1
→ t2
の順で結合するように指定しています。
mysql> explain SELECT /*+ JOIN_ORDER(t1,t2) */ * FROM t1 > JOIN t2 ON t1.col1 COLLATE utf8mb4_general_ci=t2.col1; +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------+ | 1 | SIMPLE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100.00 | NULL | | 1 | SIMPLE | t2 | NULL | ref | col1 | col1 | 43 | func | 1 | 100.00 | Using where; Using index | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------+
しかし、