Mysql2 :: Error:指定的密钥太长;仅具有87个db字段的表的最大键长为767字节

时间:2018-12-28 08:07:58

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

我的Rails模型具有87个db列的表,但是当我尝试添加任何额外的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

3 个答案:

答案 0 :(得分:1)

为此问题苦苦挣扎了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

再次添加了相同的索引

答案 1 :(得分:0)

MySQL在InnoDB中的前缀限制为767个字节,在MYISAM中为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

答案 2 :(得分:0)

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