AWS RDSへのimport時に「Specified key was too long;」で失敗したときの対策

株式会社[NoSchool](https://corp.noschool.asia)でCTOをしている@mejilebenです。
AWS RDSに入門しているとちょっと詰まったことがあったので記事に書きました。

# TL;DR
RDSにデータをインポートしようとSQLを流し込んだら

```bash:
ERROR 1071 (42000) at line 27705: Specified key was too long; max key length is 767 bytes
```

と怒られました。この対策には``innodb_large_prefix``を``1``に設定する必要があるのですが、RDSではコマンドラインからMySQLの設定値を更新できませんでした。

AWS Consoleから「パラメーターグループ」なるものを編集することで対応したので、そのログを書きます。

# インポート時のコマンド
[MySQLのデータインポート・エクスポート - Qiita](https://qiita.com/rato303/items/2e614f23e5feee150ffc)
を参考に実行しました。標準入力からSQLを流し込みました。

# なぜエラーが起きたのか
## Keyに設定した文字長が長すぎた
テーブルのKeyに指定しているカラムのバイト数が、インデックスの限界で規定されているバイト数を超えたから起きたエラーです。

[MySQLのインデックスサイズに767byteまでしかつかえない問題と対策](https://blog.e2info.co.jp/2017/04/17/mysql%E3%81%AE%E3%82%A4%E3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9%E3%82%B5%E3%82%A4%E3%82%BA%E3%81%AB767byte%E3%81%BE%E3%81%A7%E3%81%97%E3%81%8B%E3%81%A4%E3%81%8B%E3%81%88%E3%81%AA%E3%81%84/)より、UTF-8を指定している場合は1文字あたりのバイト数が4バイトになることがあり、``varchar(255)``のカラムではその4倍が限界値である``767``をゆうに越してしまいます。

あまりに文字長が長いとインデックスを貼っても効果が薄れるような背景があるのでしょうか。そのへんはまた詳しく調べてみるとして・・・

今回私が実行した文でエラーが起きたのは以下の箇所です。

```sql:sql
CREATE TABLE `hogehoge` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `hoge` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `deleted_at` timestamp NULL DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name_unique` (`name`),
  UNIQUE KEY `hoge_unique` (`hoge`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

``CHARSET``が``utf8mb4``になっており、KEYを貼っているカラムが``varchar(255)``なので、見事に767バイトを超えてしまうことがわかります。

## 回避方法
テーブルの文字コードを変えたり、バイナリに変換するなりの方法が先のブログでは紹介されていますが、**面倒くさい**のでやりたくないと思いました。

そこで、[innodb_large_prefixを使ってERROR 1071を回避する](https://yakst.com/ja/posts/734)に書いてあるとおり、``innodb_large_prefix``を``1``に設定することで回避しようとしました。

要はバイト数を超えても怒られないように、データベース側の設定値を変えてしまうという発想です。

### RDSではset globalコマンドが実行できない
これで回避できると一安心したのですが、そうは行きませんでした。

```bash:
mysql> set global innodb_large_prefix = ON;
ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER privilege(s) for this operation
```

権限不足でコマンドが実行できません。
これは[[AWS] RDS/MySQLではユーザにSUPER権限が付与できない – 端くれプログラマの備忘録](http://www.84kure.com/blog/2018/12/26/aws-rds%e3%81%aemysql%e3%81%a7%e3%81%af%e3%83%a6%e3%83%bc%e3%82%b6%e3%81%absuper%e6%a8%a9%e9%99%90%e3%81%8c%e4%bb%98%e4%b8%8e%e3%81%a7%e3%81%8d%e3%81%aa%e3%81%84/)
にかかれている通り、そもそも**AWS RDSではユーザーにSUPER権限を付与することができない**ので、解決不能な問題だということがわかりました。

ということは、今回のようにMySQLの設定値を変更することはRDSだと叶わないのでしょうか。

### RDSでMySQLの設定値を変更するには

そんなわけないと思いながら必死にググっていると、
[mysql - Amazon RDS unable to execute SET GLOBAL command - Stack Overflow](https://stackoverflow.com/questions/31147206/amazon-rds-unable-to-execute-set-global-command)
ちょうど同じ状況のStackOverflowを見つけました。

``use an RDS parameter group``ということで、RDSの「パラメーターグループ」なるものを使いなさいと書いてあります。

RDSのConsoleを開いてみると、下記画像のように、「設定」タブの左下に **「パラメーターグループ default:mysql5.7」** と書いてあることが読み取れます。
<img width="474" alt="スクリーンショット 2019-03-26 20.08.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/156567/98922122-b1e3-4c7e-583b-24715bb048a5.png">

パラメーターグループをクリックしてみると

<img width="1158" alt="スクリーンショット 2019-03-26 20.15.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/156567/893227eb-2dd8-c270-e488-d5c171eb048a.png">

こんな画面に飛びます。これはdefaultのパラメーターグループで編集不可なので、

<img width="1160" alt="スクリーンショット 2019-03-26 20.22.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/156567/95975d15-9d1c-db0e-fbec-5772eba842e5.png">

に戻って「パラメーターグループの作成」からパラメーターグループを作ります。

作り終わったら先程と同様、パラメーターグループ名をクリックして詳細に飛び、``innodb_large_prefix``と入力して、

<img width="712" alt="スクリーンショット 2019-03-26 20.22.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/156567/64422553-e76f-a20c-2d64-17ac8ac7f65a.png">

出てきた``innodb_large_prefix``に対して値``1``を設定します。

<img width="633" alt="スクリーンショット 2019-03-26 20.24.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/156567/b06fa5fa-11da-82f3-6043-4b7ebf8a4541.png">

ここまで終わったら、RDSのデータベースの方の画面に戻りまして、画面右上の「変更」を押します。

<img width="451" alt="スクリーンショット 2019-03-26 20.24.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/156567/c7dae86a-e07f-7d0a-ac8e-eab344c2a31e.png">

ここからパラメーターグループを変更できます。

ここで注意が2点ありまして、

* **変更後は設定が反映されるまで数分かかります**
* **パラメーターグループが対象となっているMySQLのバージョンと本体のバージョンがズレていたらそもそも設定できません**

という罠がありますのでお気をつけください。また、確証はできないのですが、削除保護をONにしているとどうやら再起動してくれなくて設定値が反映されない気がします。もしいつまでたっても反映されなかったらそちらも確認してください。

ここまで終わったら設定値を確認しに行きましょう。新しいパラメーターグループに変わっているはずです。

<img width="462" alt="スクリーンショット 2019-03-26 20.03.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/156567/c4669220-82b8-eb3a-8ff0-0764b93d858c.png">

ここまで終わったら再度importコマンドを走らせましょう。
以上です。

RDSのパラメーターグループは初耳だったので、勉強になりました。

# 最後に
僕が働いている[NoSchool](https://portal.noschool.asia/)では仲間を募集中です！
創業期真っ只中、社員は僕と社長の2人きりでEdTechを変えに行ってます！

興味あればお茶でもしましょう。Twitterからの連絡でも大歓迎です！
https://www.wantedly.com/companies/noschool