MySQL8.0の初期設定で検討するポイント（Docker編）

# 記事の趣旨
MySQL8.0を開発環境に導入する際に
初期設定として検討するべきポイント5点をまとめました。

# 初期設定例
MySQL8.0の初期設定例（Docker）です。
（システム要件によって設定すべき値は変わると思いますので一例です）

* docker-compose.yml
```
services:
  mysql8:
    image: mysql:8
    command:
      --collation-server=utf8mb4_0900_bin
      --transaction-isolation=READ-COMMITTED
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password
      TZ: Asia/Tokyo
    ports:
      - 63306:3306
```

* DockerによるMySQL起動（docker-compose.ymlを配置したディレクトリで実施）
```
docker compose up -d
```

* MySQL接続（Windowsコマンドプロンプトから接続して確認している為、接続元の文字コードにUTF-8＝65001を指定）
```
chcp 65001
mysql -u root -p -h localhost -P 63306
```

ポイント5点について、実例をまじえながら
解説したいと思います。

# 【ポイント1】DBサーバの文字コード
MySQL8.0ではデフォルトで
`character_set_server＝utf8mb4`となっていました。

https://dev.mysql.com/doc/refman/8.0/ja/server-system-variables.html

https://dev.mysql.com/doc/refman/8.0/ja/charset-unicode-utf8mb4.html

```
mysql> SHOW VARIABLES LIKE 'character%';
+--------------------------+--------------------------------+
| Variable_name            | Value                          |
+--------------------------+--------------------------------+
| character_set_client     | utf8mb4                        |
| character_set_connection | utf8mb4                        |
| character_set_database   | utf8mb4                        |
| character_set_filesystem | binary                         |
| character_set_results    | utf8mb4                        |
| character_set_server     | utf8mb4                        |
| character_set_system     | utf8mb3                        |
| character_sets_dir       | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+
```

utf8mb4なので、日本語はもちろん、🍣（寿司）などの絵文字も扱えます。
通常はそのままで問題ないかと思います。
デフォルトでutf8mb4なので、上記「初期設定例」では設定しておりません。

参考までにMySQL5.7のデフォルトはlatin1なので
docker-compose.ymlのcommandに`--character-set-server＝utf8mb4`などを設定することで
日本語を扱えるようになります。
https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html

# 【ポイント2】照合順序
MySQL8.0ではデフォルトで
`collation_server＝utf8mb4_0900_ai_ci`となっていました。

https://dev.mysql.com/doc/refman/8.0/ja/server-system-variables.html

```
mysql> SHOW VARIABLES LIKE 'collation_server';
+------------------+--------------------+
| Variable_name    | Value              |
+------------------+--------------------+
| collation_server | utf8mb4_0900_ai_ci |
+------------------+--------------------+
```

`utf8mb4_0900_ai_ci`なので、あ＝ぁ、は＝ぱ のように類似文字を同一視して扱います。

```
mysql> CREATE DATABASE d;
mysql> USE d;
mysql> CREATE TABLE t (c VARCHAR(20));
mysql> INSERT INTO t (c) VALUES('🍣あは');

mysql> SELECT * FROM t WHERE c = '🍣ぁぱ';
+------------+
| c          |
+------------+
| 🍣あは    |
+------------+
```

上記「初期設定例」のように
docker-compose.ymlのcommandに`--collation-server=utf8mb4_0900_bin`などを設定することで
類似文字を別の文字として扱えるようになります。
同一視させたくない場合は、そのように設定したほうがよいかもしれません。

```
mysql> CREATE DATABASE d;
mysql> USE d;
mysql> CREATE TABLE t (c VARCHAR(20));
mysql> INSERT INTO t (c) VALUES('🍣あは');

mysql> SELECT * FROM t WHERE c = '🍣ぁぱ';
Empty set (0.00 sec)

mysql> SELECT * FROM t WHERE c = '🍣あは';
+------------+
| c          |
+------------+
| 🍣あは    |
+------------+
```

また、参考までにMySQL5.7では`utf8mb4_0900_bin`を扱えません。
類似の照合順序である`utf8mb4_bin`を使用する場合、pad属性がPAD SPACEなので末尾のスペースが無視して比較されます。
注意すべきポイントかと思います。

https://dev.mysql.com/doc/refman/5.7/en/string-comparison-functions.html
https://dev.mysql.com/doc/refman/8.0/ja/charset-unicode-sets.html

```
【MySQL5.7でutf8mb4_binを使用】

mysql> CREATE DATABASE d;
mysql> USE d;
mysql> CREATE TABLE t (c VARCHAR(20));
mysql> INSERT INTO t (c) VALUES('あ');

mysql> SELECT * FROM t WHERE c = 'あ ';
+------------+
| c          |
+------------+
| あ         |
+------------+
```


# 【ポイント3】トランザクション分離レベル
MySQL8.0ではデフォルトで`REPEATABLE READ`が設定されます。
ギャップロックまたはネクストキーロックが行われるので
処理の内容によっては、ロックタイムアウトやパフォーマンス低下が懸念されます。
システム要件にもよりますが、`READ COMMITTED`にすることも検討したほうがよいかもしれません。
上記「初期設定例」のように
docker-compose.ymlのcommandに`--transaction-isolation=READ-COMMITTED`で設定できます。

https://dev.mysql.com/doc/refman/8.0/ja/innodb-transaction-isolation-levels.html

# 【ポイント4】タイムゾーン
MySQL8.0ではデフォルトでUTC時間なので、日本時間にするよう
タイムゾーンを設定しました。`TZ: Asia/Tokyo`
日本だけで使用するシステムであれば、そちらがよいかもしれません。

```
mysql> SELECT now();
+---------------------+
| now()               |
+---------------------+
| 2022-06-18 03:00:00 |
+---------------------+

↓ TZ: Asia/Tokyo設定後

mysql> SELECT now();
+---------------------+
| now()               |
+---------------------+
| 2022-06-18 14:00:00 |
+---------------------+
```


# 【ポイント5】SQLモード
SQLモードはMySQL8.0のデフォルトで次のようになっていました。
古いMySQLのデフォルトより、厳密にチェックされているなという印象です。

特に問題ないのであればそのまま使用するのでもよいですし
変更するのであれば
docker-compose.ymlのcommandにて`--sql-mode="…"`で設定できます。

```
mysql> SELECT @@SESSION.sql_mode;
+-----------------------------------------------------------------------------------------------------------------------+
| @@SESSION.sql_mode                                                                                                    |
+-----------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+-----------------------------------------------------------------------------------------------------------------------+
```

https://dev.mysql.com/doc/refman/8.0/ja/sql-mode.html

# まとめ
MySQL8.0の初期設定例を記載しました。
システム要件次第でカスタマイズしていくとよいのではないでしょうか。

本記事はDockerを使用する前提で記載していますが、my.iniでの設定や
Aurora MySQLバージョン3（MySQL8.0互換）にも応用できるかと思います。

https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.MySQL80.html