Mysql Specified key was too long 解决方案

昨晚在执行migration db变更时,报了一个错误:

CREATE TABLE `xxxx_configs` (
        `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
        `rules` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '例如:gantts_setting_var1_var2,var1=workspace_id,var2=user_id,具体规
则在代码中设置',
        `abc` VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'xxx',
        `def` int(11) NOT NULL DEFAULT 0 COMMENT,
        `ghi` TINYINT UNSIGNED NOT NULL DEFAULT '0' COMMENT '0(未启用), 1(启用)',
        PRIMARY KEY (`id`),
        UNIQUE INDEX `rules` (`rules`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;;

Reason: Specified key was too long; max key length is 767 bytes

分析:

对于报错信息“: Specified key was too long; max key length is 767 bytes”,其实意思就是“索引字段长度太长,超过了767bytes”。

mysql的varchar主键只支持不超过767个字节或者768/2=384个双字节 或者767/3=255个三字节的字段 而GBK是双字节的,UTF8是三字节的。

那么问题来了,为什么内网版库执行正常,但是SaaS版执行异常呢?

(1) 字符集设置不同?

第一个想法是查看两个库的字符集设置是不是不一样,果然内网库的字符集character_set_database=lantin1,而saas库的字符集character_set_database= utf8。这时候,我很天真的以为可能是因为建表的时候没有指定字符集,所以在导入测试库的时候默认使用utf-8字符集,导致Specified key was too long。所以就更改了saas库中默认的字符集,但是导入数据的时候依然还是报同样的错误。而且我在建表的语句中发现了,其实原来就已经指定了字符集,都是UTF8(CHARSET=UTF8),所以字符集设置不同并不是问题的症结所在。下面是用show variable_name like ‘%character_set%’的展示结果:

内网库
云端库

(2)存储引擎惹的祸?

我查了一下,内网的SQL语句和SaaS的SQL语句是一致的,同一条语句指定的engine是一样的,所以也并非是engine的锅

(3)Mysql版本的锅?

查了一圈资料,在MySQL 5.6及之前的版本,使用InnoDB作引擎的表的索引大小要小于767B,对于MyISAM的限制则是1000B。在MySQL5.7之后此限制扩展到了3027B

内网是5.7版本的SQL, SaaS版是 基于MariaDB 10.1.9设计(兼容Mysql 5.6) ,应该是Mysql 5.5的版本(Server version: 5.5.5-10.1.44-MariaDB)

(4)解决方法?

减少索引列的长度 将varchar(512) 改成 varchar(255)

参考文章:
https://cloud.tencent.com/developer/article/1005696
https://blog.csdn.net/weixin_36210698/article/details/81568230