Mysql2::Error: Specified key was too long; max key length is 767 bytes for table having only 87 db fields
Mysql2::Error: Specified key was too long; max key length is 767 bytes for table having only 87 db fields
我有 rails 模型,其中 table 有 87 个数据库列,但是当我尝试添加任何额外的数据库列时,它失败了
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
我不明白为什么它不允许添加额外的 table 列
Q. 为什么我没有得到 Mysql2::Error: Specified key was too long
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
在为这个问题奋斗了 3 天之后,@muistooshort 在评论中说的一件事让我找到了正确的解决方案。
你可能想在他的评论中重新审视你的数据库设计,困扰了我几天。所需要的只是正确的方向(在那条评论中)并且我解决了这个问题。
注意:有问题的数据几乎没有被操纵以隐藏项目架构结构。
我在添加新列时遇到问题,如错误日志中所述,但这不是因为在 table 中添加了新列。这是由于数据库中存在 table 结构。
当我从 config/schema.rb
复制 table 模式和索引时,我才知道,以创建相同的新 table 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
再次添加了相同的索引
创建数据库 utf8_general_ci 然后没问题
我有 rails 模型,其中 table 有 87 个数据库列,但是当我尝试添加任何额外的数据库列时,它失败了
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
我不明白为什么它不允许添加额外的 table 列
Q. 为什么我没有得到 Mysql2::Error: Specified key was too long
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
在为这个问题奋斗了 3 天之后,@muistooshort 在评论中说的一件事让我找到了正确的解决方案。
你可能想在他的评论中重新审视你的数据库设计,困扰了我几天。所需要的只是正确的方向(在那条评论中)并且我解决了这个问题。
注意:有问题的数据几乎没有被操纵以隐藏项目架构结构。
我在添加新列时遇到问题,如错误日志中所述,但这不是因为在 table 中添加了新列。这是由于数据库中存在 table 结构。
当我从 config/schema.rb
复制 table 模式和索引时,我才知道,以创建相同的新 table 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
再次添加了相同的索引创建数据库 utf8_general_ci 然后没问题