我在rails中进行了以下迁移:
class AddMissingIndexes < ActiveRecord::Migration[5.1]
def change
# Applications
add_index :applications, :evid, length: { evid: 255 }
end
end
这在我的测试环境
中似乎运行顺利但是,当我在生产环境中运行迁移时 我收到此错误:
Mysql2::Error: Specified key was too long; max key length is 767 bytes: CREATE INDEX `index_applications_on_evid` ON `applications` (`evid`(255))
我正在尝试使用this question
中的第二个答案来解决此问题class AddMissingIndexes < ActiveRecord::Migration[5.1]
def change
# Applications
add_index "applications", ["evid"], :name => :evid, :length => { :evid => 255 }
end
end
但是,在对架构进行任何进一步更改之前,我想确保此方法有效。因此,我需要能够在测试环境中重现此错误。
测试环境:
+-------------------------+------------------+
| Variable_name | Value |
+-------------------------+------------------+
| innodb_version | 5.5.62 |
| protocol_version | 10 |
| slave_type_conversions | |
| version | 5.5.62-0+deb8u1 |
| version_comment | (Debian) |
| version_compile_machine | x86_64 |
| version_compile_os | debian-linux-gnu |
+-------------------------+------------------+
生产环境
+-------------------------+---------------------+
| Variable_name | Value |
+-------------------------+---------------------+
| innodb_version | 5.6.40 |
| protocol_version | 10 |
| slave_type_conversions | |
| version | 5.6.40-log |
| version_comment | Source distribution |
| version_compile_machine | x86_64 |
| version_compile_os | Linux |
+-------------------------+---------------------+
使用SHOW GLOBAL VARIABLES LIKE 'innodb_%';
我可以看到我的测试环境数据库,这就是我发现本地数据库环境具有以下变量的原因:
测试环境
innodb_file_format=Barracuda;
innodb_large_prefix=1;
innodb_file_per_table=1;
innodb_file_format_max=Barracuda;
innodb_strict_mode=1;
character_set_server='utf8mb4';
生产环境
innodb_file_format=Antelope;
innodb_large_prefix=OFF;
innodb_file_per_table=ON;
innodb_file_format_max=Antelope;
innodb_strict_mode=OFF;
character_set_server='utf8mb4';
我试图重现我的生产环境,将变量一次设置为1。但无济于事。
答案 0 :(得分:1)
在测试和生产环境中都运行SHOW CREATE TABLE applications\G
。我预计差异将是:
测试:
CREATE TABLE `applications` (
...
`evid` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
生产:
CREATE TABLE `applications` (
...
`evid` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
如错误所述,索引必须能够容纳767个字节。 utf8字符集为每个字符计算了3个字节,达到了此限制,因此3 * 255 = 765,可以满足要求。
而utf8mb4每个字符计数4个字节。 4 * 255 = 1020,太长。
使用utf8mb4时,可以索引VARCHAR(191),以保持767个字节以内。
或者,您可以使用更新的InnoDB行格式来支持最大3072字节的索引大小。参见mysql change innodb_large_prefix
如果要避免此类意外,在测试和生产中运行相同版本的MySQL非常重要,并确保使MySQL配置选项尽可能接近,并确保表定义相同
使用innodb配置变量重新询问您的问题。
我看到您的生产环境具有设置,这意味着它无法使用梭子鱼文件格式定义表,这意味着没有动态行格式,这意味着没有innodb_large_prefix
。
您需要使设置与您的测试环境相匹配,然后您可能需要重建表,以便它实际上是梭子鱼格式且具有动态行格式。
我还(再次)建议您将测试服务器升级到生产中运行的相同MySQL版本。
还比较其他配置设置,以查看是否存在其他差异(除了适合与生产环境不同的那些差异外,例如innodb_buffer_pool_size)。
您还应该确保使用与技术堆栈其他部分相同的版本,例如Linux版本,Ruby版本等。如果您对版本不兼容感到惊讶,这是众所周知的项目不稳定和计划延迟的来源,如果您无法使开发和测试环境与生产环境匹配。