【问题标题】:Rails creating schema_migrations - Mysql2::Error: Specified key was too longRails 创建 schema_migrations - Mysql2::Error: Specified key was too long
【发布时间】:2012-07-25 07:34:40
【问题描述】:

我使用的是 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`)

经过数小时的研究,我找到了以下解决方案:

1。将 MySQL 变量 innodb_large_prefix 更改为 true(或 ON)

这不起作用。我在我的 Linux 服务器、我的 Mac 甚至 Windows 上都试过了——它就是不工作。

2。 Monkeypatch ActiveRecord::SchemaMigration.create_table

我不需要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 语句中,但我也没有成功使用此解决方案。问题是当原版已经到位时,我无法加载此补丁。换句话说 - 我的补丁加载 before 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 到位后加载此文件并使此补丁生效?

你有什么建议吗?如果这对您没有意义,我可以澄清这个问题的任何部分。尽管问我。我被这个问题困扰太久了。

【问题讨论】:

  • 在做任何 Rails 工作之前,您是否考虑过手动创建 schema_migrations(包含合理的列大小)?
  • 是的,我已经考虑过了,但恐怕这不适用于rake db:test:clone?此外,它会使生产服务器/开发人员机器上的设置复杂化,因为我必须运行一些脚本来预初始化数据库并创建此表。

标签: mysql ruby-on-rails activerecord rails-migrations


【解决方案1】:

767 键应该可以工作。确保使用utf8 编码,而不是utf16。 我有同样的问题,我的错误是我不小心创建了utf16 数据库

【讨论】:

  • 在database.yml中添加>> "encoding: utf8"
  • 此错误是由于数据库使用utf8mb4 编码引起的,该编码专门用于允许表情符号和其他 utf8 字符。您提供的将返回到 utf8,不支持扩展 unicode。
  • 您可以使用 utf8mb4 将索引列限制为 191 或更少。出现问题是因为在 uft8mb4 中,maxlength 以字节为单位。
  • 成功了! +1 并且 collation 设置为 utf8_general_ci
【解决方案2】:

我建议您删除数据库并按照以下说明重新创建一个新数据库:

 mysql -u root -p -e "CREATE DATABASE {DB_NAME} DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"

【讨论】:

    【解决方案3】:

    我对长度为 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 based only on the string's content

    使字符串更短,它应该可以工作,但取决于您的需要

    或在迁移中使用全文,如下所示:

    class AddVersionToUsers < ActiveRecord::Migration
      def change
        add_column :users, :version, :string, limit:2000
        add_index  :users, :version, type: :fulltext
      end
    end
    

    参考:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-12
      • 1970-01-01
      • 2012-06-08
      • 2019-04-09
      • 2014-08-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多