hello-world.jp.net
webエンジニアのメモ。とりあえずやってみる。

Mysql2::Error: Specified key was too long; max key length is 767 bytes limit

公開日時

railsでactive_adminのmigrationを行う際に以下のようなエラーが出ました

Mysql2::Error: Specified key was too long; max key length is 767 bytes limit

index対象のカラム量が767バイトを超えると出るエラーのようです。

MySQLのencodingがutf8の場合は3バイトのため、255 * 3 = 765バイト で767バイト以下に収まります。

しかし、utf8mb4の場合は4バイトのため、255 * 4 = 1,020 バイトとなり、767バイトを超えてしまうためエラーが発生します。

今回utf8mb4を使用していたため、上記エラーが発生しました。

対応方法としては、my.cnfに設定を書いてindexのkey lengthを拡張する、もしくはカラムのlimitを下げるというので対応できました。

方法1. indexのkey lengthを拡張する

/etc/my.cnf に以下を記述すればリミットを3072byteに拡張することができます。

[mysqld]
innodb_file_per_table
innodb_file_format=barracuda
innodb_large_prefix = 1

方法2. カラムのlimitを下げる

migrationファイル内のカラムに「limit: 191」を設定することで、191 * 4 = 764バイトとなり制限以内に抑えることができます。

t.string :email, limit: 191

もしくは config/initializers/mysqlpls.rb に初期化設定を書いて、一括で更新する方法もありました。

今回は開発環境だけ適用したかったので、以下のようにしました

require 'active_record/connection_adapters/abstract_mysql_adapter'

if Rails.env.development?
  module ActiveRecord
    module ConnectionAdapters
      class AbstractMysqlAdapter
        NATIVE_DATABASE_TYPES[:string] = { :name => "varchar", :limit => 191 }
      end
    end
  end
end

方法2の場合は、カラムの最大長が減ってしまうので、可能であれば方法1のようにmy.cnfに追記するやりかたで対応するのがよさそうです。

2014/11/3 追記 上記の設定を行った別環境で

bundle exec rake db:create

を実行しようとしたところ、再度

Mysql2::Error: Specified key was too long; max key length is 767 bytes limit

のエラーが出てしまいました。

調べてみるとmysql側のROW_FORMATがCOMPACT設定になっていたのが原因でした。

上記設定はROW_FORMATがDYNAMICかCOMPRESSEDのとき有効とのことなので、

ActiveRecordをutf8mb4で動かす」にあったactive_recordの設定を記述して、

# config/initializers/ar_innodb_row_format.rb

ActiveSupport.on_load :active_record do
  module ActiveRecord::ConnectionAdapters

    class AbstractMysqlAdapter
      def create_table_with_innodb_row_format(table_name, options = {})
        table_options = options.merge(:options => 'ENGINE=InnoDB ROW_FORMAT=DYNAMIC')
        create_table_without_innodb_row_format(table_name, table_options) do |td|
          yield td if block_given?
        end
      end
      alias_method_chain :create_table, :innodb_row_format
    end

  end
end

再度 db:create を実行したらうまくDB作成できました。

参考


Related #MySQL

[mysql][rails]Character set 'utf8mb4' is not a compiled character set and is not specified in the '/usr/share/mysql/charsets/Index.xml' file

mysql5.1が動いていた環境をmysql5.6にアップデートした後、rake db:createで utf8mb4のDBを作成しようとしたところ以下のエラーが発生

[rails][mysql]Can't connect to local MySQL server through socket '/tmp/mysql.sock'

Railsアプリを起動しようとした際に `Can't connect to local MySQL server through socket '/tmp/mysql.sock'` というエラーが発生。

vagrantでmysqlレプリケーション実験環境をお手軽作成

mysqlのレプリケーション設定をする機会があったので、実環境で試す前に実験してみたいと思い、vagrantを使ってレプリケーション設定用のサーバを立ててみました。

ログファイルを空にする方法

ローカル環境ではmysqlのクエリログを出力するようにしているのですが、放置していたらかなりの容量になってきたので一度空にしようと思って調べてみました。