当我使用rake db:schema:load
在运行MySQL 5.6.22的笔记本电脑上创建下表时,它加载正常:
create_table "inv_audits", force: :cascade do |t|
t.integer "inv_node_id", limit: 2, null: false
t.integer "inv_object_id", limit: 4, null: false
t.integer "inv_version_id", limit: 4, null: false
t.integer "inv_file_id", limit: 4, null: false
t.string "url", limit: 16383
t.string "status", limit: 18, default: "unknown", null: false
t.datetime "created", null: false
t.datetime "verified"
t.datetime "modified"
t.integer "failed_size", limit: 8, default: 0, null: false
t.string "failed_digest_value", limit: 255
t.text "note", limit: 65535
end
但是,当我尝试在运行5.7.21的桌面上执行相同的操作时,它会失败并显示Mysql2::Error: Row size too large.
跟踪生成的SQL是:
CREATE TABLE `inv_audits` (
`id` int(11) auto_increment PRIMARY KEY,
`inv_node_id` smallint NOT NULL,
`inv_object_id` int(11) NOT NULL,
`inv_version_id` int(11) NOT NULL,
`inv_file_id` int(11) NOT NULL,
`url` varchar(16383),
`status` varchar(18) DEFAULT 'unknown' NOT NULL,
`created` datetime NOT NULL,
`verified` datetime,
`modified` datetime,
`failed_size` bigint DEFAULT 0 NOT NULL,
`failed_digest_value` varchar(255),
`note` text
) ENGINE=InnoDB
为什么这会在5.7中失败但在5.6中成功?
两台机器都是64位Mac,运行macOS High Sierra(10.13.4)。
答案 0 :(得分:4)
字符类型列的字符集,尤其是url
VARCHAR
列。
数据类型定义VARCHAR(16383)
上的length属性指定了多个字符。
但InnoDB行大小限制为 bytes 。
对于单字节字符集(例如latin1),该列的最大字节数为16383(加上隐藏长度的空间)。这没关系。
使用多字节字符集,例如utf8(每个字符最多3个字节)或utf8mb4(每个字符最多4个字节),所需的字节数将超过InnoDB行的最大允许字节数。
在5.6系统上,我们可以做一个
SHOW CREATE TABLE inv_audits
如果没有为列指定字符集/排序规则,则表的默认值有效。 (可以指定表的字符集,如果不是,则继承数据库的默认集。)
要获取在5.7上创建的表,作为测试,将VARCHAR大小减小到当前值的1/4,然后查看CREATE TABLE。
SHOW CREATE TABLE inv_audits
它将是一个多字节字符集,如utf8或utf8mb4。
我敢打赌,问题的根本原因是默认字符集在5.6和5.7中是不同的。