Edited at

Laravel5.4以上、MySQL5.7.7未満 でusersテーブルのマイグレーションを実行すると Syntax error が発生する


はじめに

古い備忘録だが、いまだに定期的にアクセスがあるので全面的に加筆修正した。

PHPは7系に追従していても、MySQLのバージョンはいまだ5.5~5.6、という環境も多いのだろう。


前提


  • Laravel5.4以上

  • MySQL5.7.7未満


現象

上記環境のもとで、$ php artisan make:authで自動作成されるマイグレーションファイルに対し、

$ php artisan migrate を実行すると、以下のエラーが発生する。


[Illuminate\Database\QueryException]

SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was t

oo long; max key length is 767 bytes (SQL: alter table users add unique

users_email_unique
(email))

[PDOException]

SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was t

oo long; max key length is 767 bytes



原因


1. Laravel5.4から標準charasetがutf8mb4に変わった

標準charasetがutf8mb4となったことで1文字あたりの最大byte数が4bytesに増えた。


2. MySQL5.7.7未満ではユニーク制約を付けたカラムは最大767bytes

マイグレーションファイルにvarcharカラムの大きさを指定しなかった場合、varchar(255) のカラムが作成される。

 $table->string('email')->unique();

一方、MySQL5.7.7以前のバージョンでは、PRIMARY_KEYおよびUNIQUE_KEYを付けたカラムには最大767bytesまでしか入らない。


4bytes,255文字では767bytesを超えてしまう。これがエラーの原因。


対策

対策としては以下の3つが考えられる。


  1. MySQLのバージョンを最新にする

  2. 使用するcharasetをutf8mb4から変更する

  3. カラムの最大長を変更し、767bytes以上の文字列が入らないようにする


対策1:MySQLのバージョンを最新にする

特段の事情がなければベストの対応。MySQL5.6系のPremier Support期限は2018年2月に終了している。


対策2:使用するcharasetをutf8mb4から変更する

Laravel5.3まではcharsetの標準設定はUTF-8だった。

config/database.php よりcharsetを以下のように変更すれば、Laravel5.3以前と同じ挙動で使用することができる。

ただし、絵文字 :sushi: は使えなくなる。

'charset' => 'utf8',

'collation' => 'utf8_unicode_ci',


対策3:カラムの最大長を変更し、767bytes以上の文字列が入らないようにする

varchar(191) のカラムを作成すれば、191 * 4 = 764bytesのため、エラーが発生しない。

//個別で指定する例

$table->string('email', 191)->unique();

上記のようにカラムごと個別に最大長を指定してもよいが、

app\Providers\AppServiceProvider.php に以下の記載を追加することで、最大長未指定時のdefault値を変更することが可能である。

use Illuminate\Support\Facades\Schema;

public function boot()
{
Schema::defaultStringLength(191);
}

これでマイグレーションを実行すれば、正常に動作する。


参考URL


  1. https://laravel-news.com/laravel-5-4-key-too-long-error

  2. http://d.hatena.ne.jp/tanamon/20090930/1254332746