【问题标题】:Mysql2::Error: Specified key was too long; max key length is 767 bytes for table having only 87 db fieldsMysql2::Error: 指定的键太长;对于只有 87 db 字段的表,最大密钥长度为 767 字节
【发布时间】:2019-05-26 02:18:06
【问题描述】:

我有带有 87 db 列的表的 rails 模型,但是当我尝试添加任何额外的 db 列时,它失败了

ArbitaryDatum.columns.count
 => 87

ArbitaryDatum.table_name
 => "arbitary_data"

ActiveRecord::Migration.add_column :arbitary_data, :attr51, :string

-- add_column(:arbitary_data, :attr51, :string)
   (1.4ms)  ALTER TABLE `arbitary_data` ADD `attr51` varchar(255)
Mysql2::Error: Specified key was too long; max key length is 767 bytes: ALTER TABLE `arbitary_data` ADD `attr51` varchar(255)
ActiveRecord::StatementInvalid: Mysql2::Error: Specified key was too long; max key length is 767 bytes: ALTER TABLE `arbitary_data` ADD `attr51` varchar(255)

我检查了我使用的是哪个 mysql 版本,

mysql --version
mysql  Ver 14.14 Distrib 5.5.62, for debian-linux-gnu (i686) using readline 6.3

我不明白为什么它不允许添加额外的表格列

问。为什么我没有收到Mysql2::Error: Specified key was too long

【问题讨论】:

  • 我认为您真正的问题是您有一个包含 87 列的表,特别是如果它们的名称类似于 attr51。您可能想重新审视您的数据库设计。
  • @muistooshort 请告诉我“重新访问数据库设计”是什么意思。你的意思是表模式吗?该特定表的 87 列中有 50 列命名为“attr1”到“attr2”。
  • 是的,架构。一个有 87 列的表,名字像这样闻起来很糟糕。表太宽,列太多。比如说,attr23 是什么意思?
  • data 属于 structure 结构知道哪个 attr 持有什么!我们的客户将决定哪个 attr 保存什么,他定义了结构,它定义了 50 个带有序列化哈希的 attr db 字段,这些字段有键来告诉它应该有什么名称它应该有什么类型! ****现有****
  • @muistooshort Now 改变现有的 3 年以上运行良好的字段真的很难,所以我只想简单地添加 30 个字段,但不能添加一个属性

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


【解决方案1】:

MySQL 在 InnoDB 中的前缀限制为 767 字节,在 MISAM 中为 1000 字节,

不幸的是,没有真正的解决方案。您唯一的选择是减小列的大小、使用不同的字符集(如 UTF-8)或使用不同的引擎(如 MYISAM)。在这种情况下,我将字符集切换为 UTF-8,从而将最大密钥长度提高到 255 个字符。

在迁移中将字符集设置为 UTF8

reversible do |dir|
      dir.up {
        ActiveRecord::Migration.add_column :data, :attr51, "VARCHAR(255) CHARACTER SET utf8"
      }
    end

【讨论】:

  • 感谢您的回复,但我对同一数据库中的其他表尝试了相同的操作,我可以为 text 类型的表添加超过 1000 列。所以问题是为什么它发生在这个有 87 列的data 表上?
  • 我也会检查您提供的解决方案,但我需要:text 而不是:string & 这里reversible 是什么?
  • @ray MySQL 的硬限制是每个表 4096 列,但对于给定的表,有效最大值可能会更少。确切的列限制取决于几个因素:请参阅此链接dev.mysql.com/doc/refman/5.5/en/column-count-limit.html
  • 我试过ActiveRecord::Migration.add_column :data, :attr51, "VARCHAR(255) CHARACTER SET utf8"但没有用,同样的错误。
【解决方案2】:

在为这个问题挣扎了 3 天之后,@muistooshort 在评论中说的一件事让我找到了正确的解决方案。

您可能想在他的评论中重新审视您的数据库设计,这困扰了我几天。所需要的只是正确的方向(在那条评论中),我解决了这个问题。

注意:所提供的数据很少被操纵以隐藏项目架构结构。

我在添加新列时遇到问题,如错误日志中所述,但这不是由于在表中添加新列所致。这是由于数据库中现有的表结构。

当我从 config/schema.rb 复制表架构以及索引以创建相同的新表 arbitary_data_dup 时,我才知道

  # replaced `arbitary_data` with `arbitary_data_dup`
  ActiveRecord::Migration.create_table "arbitary_data_dup", force: :cascade do |t|
    # code to add 87 columns for table
  end
  # following index threw error
  ActiveRecord::Migration.add_index "arbitary_data_dup", ["attr1", "arbitary_structure_id"], name: "index_arbitary_data_on_attr1_and_arbitary_structure_id", unique: true, using: :btree
  ActiveRecord::Migration.add_index "arbitary_data_dup", ["attr1"], name: "index_arbitary_data_on_attr1", length: {"attr1"=>191}, using: :btree
  ActiveRecord::Migration.add_index "arbitary_data_dup", ["id"], name: "index_arbitary_data_on_id", using: :btree
  ActiveRecord::Migration.add_index "arbitary_data_dup", ["arbitary_structure_id"], name: "index_arbitary_data_on_arbitary_structure_id", using: :btree

rails console 中运行上面的代码时,它抛出了同样的错误,我确定它不允许添加新列的原因,

ActiveRecord::Migration.add_index "arbitary_data_dup", ["attr1", "arbitary_structure_id"], name: "index_arbitary_data_on_attr1_and_arbitary_structure_id", unique: true, using: :btree
-- add_index("arbitary_data_dup", ["attr1", "arbitary_structure_id"], {:name=>"index_arbitary_data_on_attr1_and_arbitary_structure_id", :unique=>true, :using=>:btree})
   (52.5ms)  CREATE UNIQUE INDEX `index_arbitary_data_on_attr1_and_arbitary_structure_id` USING btree ON `arbitary_data_dup` (`attr1`, `arbitary_structure_id`) 
Mysql2::Error: Specified key was too long; max key length is 767 bytes: CREATE UNIQUE INDEX `index_arbitary_data_on_attr1_and_arbitary_structure_id` USING btree ON `arbitary_data_dup` (`attr1`, `arbitary_structure_id`) 
ActiveRecord::StatementInvalid: Mysql2::Error: Specified key was too long; max key length is 767 bytes: CREATE UNIQUE INDEX `index_arbitary_data_on_attr1_and_arbitary_structure_id` USING btree ON `arbitary_data_dup` (`attr1`, `arbitary_structure_id`)

所以我找到了它不允许添加新列的原因 -> 现有索引的名称无效。

所以我删除了该索引,然后我可以添加新列。

ActiveRecord::Migration.remove_index "arbitary_data", ["attr1", "arbitary_structure_id"]
-- remove_index("arbitary_data", ["attr1", "arbitary_structure_id"])
   (148.6ms)  DROP INDEX `index_arbitary_data_on_attr1_and_arbitary_structure_id` ON `arbitary_data`
   -> 0.1698s
 => nil 
ActiveRecord::Migration.add_column :arbitary_data, :attr51, :string
-- add_column(:arbitary_data, :attr51, :string)
   (523.3ms)  ALTER TABLE `arbitary_data` ADD `attr51` varchar(255)
   -> 0.5238s
 => nil

使用help 再次添加相同的索引

【讨论】:

    【解决方案3】:

    创建数据库为 utf8_general_ci 然后没问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-25
      • 2016-04-15
      • 2012-05-31
      • 2015-06-22
      • 2013-12-21
      • 2015-06-29
      • 2016-10-04
      • 2014-08-17
      相关资源
      最近更新 更多