[英]Rails creating schema_migrations - Mysql2::Error: Specified key was too long
我正在使用 Rails 3.2.6 和 Mysql 6.0.9(但我在 MySQL 5.2.25 上有完全相同的错误)
当我创建新数据库 ( rake db:create
) 然后当我尝试加载模式 ( rake schema:load
) 时,我收到此错误:
Mysql2::Error: Specified key was too long; max key length is 767 bytes: CREATE UNIQUE INDEX `unique_schema_migrations` ON `schema_migrations` (`version`)
经过数小时的研究,我找到了这些解决方案:
这没有用。 我在我的 Linux 服务器、我的 Mac 甚至 Windows 上都试过了——它就是行不通。
我不需要version
列的长度为 255(当它是 UTF-8 时,它需要 4*255 = 1020 字节,超过 MySQL 键的 767 字节限制)。 我也不需要它是 UTF-8,但数据库中的所有其他表都是 UTF-8,并且我已将 utf8_czech_ci 设置为默认排序规则。
实际创建 schema_migrations 表的方法如下所示:
def self.create_table
unless connection.table_exists?(table_name)
connection.create_table(table_name, :id => false) do |t|
t.column :version, :string, :null => false
end
connection.add_index table_name, :version, :unique => true, :name => index_name
end
end
您可以在Github rails/rails上阅读整个文件
所以我尝试将:limit => 100
添加到t.column
语句中,但我也没有成功使用此解决方案。 问题是当原始文件已经到位时,我无法加载此补丁程序。 换句话说——我的补丁在 ActiveRecord::SchemaMigration之前加载,所以它被覆盖了。
当我把它放在config/initializers/patches/schema_migration.rb
:
require 'active_record/scoping/default'
require 'active_record/scoping/named'
require 'active_record/base'
module ActiveRecord
class SchemaMigration < ActiveRecord::Base
def self.create_table
unless connection.table_exists?(table_name)
connection.create_table(table_name, :id => false) do |t|
t.column :version, :string, :null => false, :limit => 100
end
connection.add_index table_name, :version, :unique => true, :name => index_name
end
end
end
end
它已成功加载,但在加载原始 ActiveRecord::SchemaMigration 时被覆盖。
我试图搞砸 ActiveSupport.on_load(:active_record) 但这似乎也不起作用。
有没有办法在原始 ActiveRecord::SchemaMigration 就位后加载此文件并使此补丁起作用?
你有什么建议吗? 如果对您来说没有意义,我可以澄清这个问题的任何部分。 问我吧。 我一直坚持这个太久了。
767 密钥应该有效。 确保使用utf8
编码,而不是utf16
。 我有同样的问题,我的错误是我不小心创建了utf16
数据库
我建议您删除数据库并按照以下说明重新创建一个新数据库:
mysql -u root -p -e "CREATE DATABASE {DB_NAME} DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"
我总是有这个错误,当它不是这个错误时:
Mysql2 ::错误:指定的密钥太长; 最大密钥长度为767字节:
就是这个:
Mysql2 ::错误:指定的密钥太长; 最大密钥长度为3072字节
所以我在这里建议我使用docker和官方mysql创建一个具有此设置的新数据库
docker run -p 3306:3306 --name mysql-name -e MYSQL_ROOT_PASSWORD=name -d mysql:5.6 --innodb-large-prefix=1 --innodb-file-format=barracuda --innodb-file-per-table=1
这里重要的不是docker是数据库啊配置
innodb-large-prefix = true innodb-file-format = barracuda innodb-file-per-table = true
最后这个database.yml如下改变utf8 latin1 sswedish是因为在服务器中我看到了:
development:
host: 192.168.99.100
database: name
username: root
password: root
adapter: mysql2
charset: latin1
encoding: latin1
collation: latin1_swedish_ci
test:
host: 192.168.99.100
database: name_test
username: root
password: root
adapter: mysql2
charset: latin1
encoding: latin1
collation: latin1_swedish_ci
production:
host: 192.168.99.100
database: name
username: root
password: root
adapter: mysql2
charset: latin1
encoding: latin1
collation: latin1_swedish_ci
之后工作
bundle exec rake db:create
bundle exec rake db:migrate
我用猴子补丁做了这个,没有在这里建议的猴子补丁,它的工作原理
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.reverse_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
我对长度为 2000 的 varchar 的名为 version 的列有同样的问题
class AddVersionToUsers < ActiveRecord::Migration
def change
add_column :users, :version, :string, limit:2000
add_index :users, :version
end
end
我使用的是 latin 1 1 character 1 byte,但现在我想使用 utf8mb4 1 character 4 bytes。
像这样配置你的数据库你可以获得直到 3072 字节的索引:
docker run -p 3309:3306 --name test-mariadb -e MYSQL_ROOT_PASSWORD=Cal1mero. -d mariadb:10.2 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --innodb-large-prefix=1 --innodb-file-format=barracuda --innodb-file-per-table=1 --innodb-strict-mode=1 --innodb-default-row-format=dynamic
这对于 latin_1 来说足够了(将是 2000 字节),但对于 utf8mb4 它将是 8000 字节。 在这个键中你有一些选择
添加一个名为 hash_version 的列并在该列上实现索引。
Consistent String#hash 仅基于字符串的内容
缩短字符串,它应该可以工作,但取决于您的需要
或在您的迁移中使用全文,如下所示:
class AddVersionToUsers < ActiveRecord::Migration
def change
add_column :users, :version, :string, limit:2000
add_index :users, :version, type: :fulltext
end
end
参考:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.