Laravel5.5でphp artisan migrateした時にエラー「1071 Specified key was too long; max key length is 767 bytes」が発生

カテゴリ: Laravel

Laravel5.5でphp artisan migrateした時に下記のエラーが発生することがあります。

$ php artisan migrate

 [Illuminate\Database\QueryException]
  SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too 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 too long; max key length is 767 bytes

エラーの発生する理由

Laravelでは、バージョン5.4以降で、MySQLのデフォルトキャラクタセットがutf8mb4に変更されました。Laravelがデフォルトのキャラクタセットをutf8mb4に変更した理由は、UTF8の絵文字などをDBに正しくストア出来るようにしたためです。

utf8mb4のキャラクタセットだとデータを格納する際、1文字当たり4byteの領域が必要です。また、Laravelのマイグレーションではstring型のカラムを作ったときに、varchar(255)としてデータ型を指定します。utf8mb4のcharasetで255文字を格納する列を作った場合、データ長は最大255*4=1020byteになります。

一方で、MySQLのVer5.7.7以前の場合、テーブルのIndexに指定できるデータ長は最大767byteです。

このため、Ver5.7.7以前のMySQLに対してテーブルの作成を行うと、MySQLが許容するIndexのデータ長767Byteを超えてしまい、エラーmax key length is 767 bytesが発生します。

対応方法

対処法としては、"MySQLのバージョンを5.7.7以降にアップデートしたり、DBのcharasetをutf8mb4にしない"という選択肢もありますが、文字列型の列を作る時にデフォルトのデータ長を変更してしまうのが最も簡単です。

Laravelのマイグレーションで、create tableする時に、varcharのデータ長を191文字になるよう変更します。191文字にすると、191*4=764byteなのでindexの最大長である767byte以内に収まります

変更の対象ファイルですが、app\Providers\AppServiceProvider.phpをエディタで開いてください。

AppServiceProvider.phpを見ると、以下のようにboot()関数が空になっているので...

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
    ...

ここに、Schema::defaultStringLength(191);の1行を追加すればよいです。

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        \Illuminate\Support\Facades\Schema::defaultStringLength(191);
    }
    ...

再実行しても、Table 'users' already existsエラーが出るときは...

一度"Specified key was too long"エラーが出た後、前述の対処を行い、再度php artisan migrateを実行すると、引き続き下記のエラーが出る場合があります。

[Illuminate\Database\QueryException]
  SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'users' already exists 
  (SQL: create table `users` (`id` int unsigned not null auto_increment primary key, 
  `name` varchar(191) not null, `email` varchar(191) not null, `password` varchar (191) not null, 
  `remember_token` varchar(100) null, `created_at` timestamp null, `updated_at` timestamp null) 
  default character set utf8mb4 collate utf8mb4_unicode_ci)

これは、前回の実行でcreate tableによるテーブル作成だけ行われindexの作成に失敗したためで、再度php artisan migrateを実行したとき、既にテーブルが存在しているためです。

上記の例だとusersテーブルが問題になっているので、下記のSQLを実行してテーブルを手作業で削除してあげる必要があります。

drop table users;

テーブルをdropした後、再度php artisan migrateを実行すれば、今度こそは大丈夫なはずです。

こちらもおススメ

コメントを残す

メールアドレスが公開されることはありません。