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作成できました。