MySQL-Specified key was too long

前段时间刚换了新的工作,然后之前也在一直准备面试,入职之后又需要适应新的工作内容、新的同事、新的项目,所以博客也一直没写,也没有学习新的东西,总的来说还是有点懈怠。😭 不过最近已经在慢慢变好了。

问题来源

那么开始正题,这个问题是怎么来的呢?新的公司肯定要负责新的项目呀,那么遇到的第一个问题就向你走来了。

我在负责一个新的项目时,要上线到测试的服务器,然后首先就是 SQL 的打包上线,这问题不就来了嘛。

1
ERROR 1071 (42000): Specified key was too long; max key length is 767 bytes

字面意思如下:索引字段长度太长,最大长度是 767 字节。

很有意思的是,本地数据库都是正常的,为什么测试数据库不行呢?


问题探究

看到这个问题抛出的时候,脑子应该会出现以下的可能,分别是字符集、存储引擎、MySQL 版本不同。

字符集设置不同

这个可能性很好验证,查看了测试环境和开发环境数据库的字符集设置,果然是不一致,然后同时发现导入表的时候没有设置字符集,但是添加字符集的设置,错误依然还是会抛出。那么这个问题就跟字符集没有关系了。

存储引擎

在检查上面的字符集时,还发现了一件事情就是发现建表设置的存储引擎与实际存储表的存储不一致,仔细想想,貌似 MyISAM 存储引擎对于主键的长度是有限制的:

  • InnoBD 存储引擎,多列索引的长度限制如下:
    每列的长度不能超过 767 bytes ,所有组成索引列的长度之和不能超过 3072 bytes
  • MyISAM 存储引擎,多列索引的长度限制如下:
    每列的长度不能超过 1000 bytes ,所有组成索引列的长度之和不能超过 1000 bytes

那么接下来就是先不管 MySQL 导致是怎么做的转换,想修改默认的存储引擎

1
set global default_storage_engine="InnoDB"

这样就保证了在不修改数据源的情况下,尽可能的保证测试环境和开发环境的一致性。

更改索引字段长度

看到异常信息之后,第一反应就是是不是主键的长度设置的过长,那么我修改一下长度会不会避免这个问题?经过测试,是不行的,但是我发现可用通过别的路径来避免这个问题。通过启用 innodb_large_prefi 参数,来使得单个索引字段的长度突破 767 bytes

1
2
set global innodb_large_prefix=1;
set global innodb_file_format=BARRACUDA;

通过上面的设置,遇到的问题可以解决,但是 InnoDB 的所有组成索引列的长度之和的限制却不能避免,这个限制会仍然存在。

MySQL 版本不同

看到了这里,我想离解决问题基本上不远了,测试环境与开发环境的 MySQL 版本确实不一致,具体去看这两个版本的差异时,发现了上面的关于 InnoDB 存储引擎规定的长度限制仅限于 5.6 版本之前,5.7 版本之后已经修改到了 3072 bytes


解决方案

看到了这里,那么解决方案就已经很明确

  • 不升级版本,但可以有限解决问题。那么你可以通过更改索引前缀来解决问题,但是组成索引列的限制会依旧存在。
  • 升级版本。一劳永逸的解决问题。

引用

MySQL 经典案例分析:Specified key was too long
【mysql】关于innodb_file_format


个人备注

此博客内容均为作者学习所做笔记,侵删!
若转作其他用途,请注明来源!