Rails6.0のMySQLに関する変更点まとめ

いよいよRails6.0がリリースされますね！
個人的にRailsのDBはMySQLを使うことが多いので、Rails6.0のMySQLに関する変更点をまとめてみました。

#1. `text`カラムと`blob`カラムに`:size`オプションが追加
`text`と`blob`のサイズを変更するために、`:size`オプションが追加されました。

- 参照
 - [MySQL: Support `:size` option to change text and blob size](https://github.com/rails/rails/pull/35071)

Railsのカラムの型とMySQLのデータ型の対応は、以下のようになります。

|Railsのカラムの型|`:size`オプションの値|MySQLのデータ型|最大長             |
|:-------------:|:----------------:|:------------:|:----------------:|
|text           |       tiny       |  TINYTEXT    |255バイト          |
|text           |       なし        |  TEXT        |65,535バイト       |
|text           |      medium      |  MEDIUMTEXT  |16,777,215バイト   |
|text           |      long        |  LONGTEXT    |4,294,967,295バイト|
|binary         |       tiny       |  TINYBLOB    |255バイト          |
|binary         |       なし        |  BLOB        |65,535バイト       |
|binary         |      medium      |  MEDIUMBLOB  |16,777,215バイト   |
|binary         |      long        |  LONGBLOB    |4,294,967,295バイト|

実際にmigrationで書くとこんな感じです。

```ruby
create_table :blogs do |t|
...略
  t.text :content, size: :medium
...略
end
```

#2. DEFAULTの関数指定と式インデックスをサポート
MySQL 8.0.13から追加された、以下2つの機能をサポートするようになりました。

- DEFAULTの関数指定(`default expression`)
 - カラム定義の際、DEFAULTの値に関数や式を使える機能。
- 式インデックス(`expression indexes`)
 - インデックスを貼る際、式の値を使える機能。

- 参照
 - [Support default expression and expression indexes for MySQL](https://github.com/rails/rails/pull/34307)
 - [MySQL :: MySQL 8.0 Reference Manual :: 11.7 Data Type Default Values](https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html#data-types-defaults-explicit)
 - [MySQL :: MySQL 8.0 Reference Manual :: 13.1.15 CREATE INDEX Syntax](https://dev.mysql.com/doc/refman/8.0/en/create-index.html#create-index-functional-key-parts)

##2-1. DEFAULTの関数指定(`default expression`)
`supports_default_expression?`というメソッドが用意されており、PostgreSQLかMySQLか、MySQLなら8.0.13以降か、という判定をしています。

- 参照
 - [supports_default_expression?](https://github.com/rails/rails/blob/a2ad8f456e29f760f78333e14474868a63a22a6f/activerecord/test/cases/helper.rb#L51)

実際にmigrationの時に使うとこんな感じです。

```ruby
create_table :products, force: true do |t|
...略
  if supports_default_expression?
    t.binary :uuid, limit: 36, default: -> { "(uuid())" }
  end
...略
end
```

##2-2. 式インデックス(`expression indexes`)
こちらも`supports_expression_index?`というメソッドが用意されており、MySQLのバージョンが8.0.13以降かの判定をしています。

- 参照
 - [supports_expression_index?](https://github.com/rails/rails/blob/a2ad8f456e29f760f78333e14474868a63a22a6f/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb#L75)

実際にmigrationの時に使うとこんな感じです。

```ruby
create_table :students, force: true do |t|
...略
  t.string  :name
  t.integer :rating, default: 1
...略
  if supports_expression_index?
    t.index "(CASE WHEN rating > 0 THEN lower(name) END) DESC", name: "student_expression_index"
  end
end
```

#3. `TIME`,`DATETIME`,`TIMESTAMP`のデフォルト値の桁数指定が可能に
`TIME`,`DATETIME`,`TIMESTAMP`のデフォルト値に関する修正です。
デフォルト値の秒の少数部の桁数を、0~6で指定できるようになりました。

- 参照
 - [Fix default value for mysql time types with specified precision](https://github.com/rails/rails/pull/33280)

以下のように`default:`オプションを指定すると、デフォルト値に`CURRENT_TIMESTAMP(6)`が設定されます。

```ruby
create_table :enquetes, force: true do |t|
...略
  t.datetime "answered_at", precision: 6, default: -> { "current_timestamp(6)" }, null: false
end
```

#4. デフォルトの文字セットが`utf8mb4`に
Rails5.2まではMySQLのデフォルトの文字セットは`utf8`でしたが、Rails6.0からは`utf8mb4`に変更になりました。

- 参照
 - [Use utf8mb4 character set by default for MySQL database](https://github.com/rails/rails/pull/33608)

絵文字などをサポートするために、変更したようです。

#5. 対応バージョンがMySQL 5.5.8以降に
Rails5.2までは`ActiveRecord`がサポートするMySQLのバージョンは5.1.10以降でしたが、Rails6.0からは5.5.8以降に引き上げられました。

- 参照
 - [Validate if `utf8mb4` character set and longer index key prefix is supported](https://github.com/rails/rails/pull/33853)

MySQL 5.1系では`utf8mb4`をサポートしていないために、対応したようです。

#6. `ROW_FORMAT=DYNAMIC`がデフォルトオプションに
`ROW_FORMAT=DYNAMIC`が`create table`時のデフォルトオプションになりました。

- 参照
 - [MySQL: `ROW_FORMAT=DYNAMIC` create table option by default](https://github.com/rails/rails/pull/34742)

これでMySQL 5.6までで`utf8mb4`を扱う場合に、設定しやすくなりました。