在为数据库某字段(varchar(255))创建索引的时候出现如下问题:
Specified key was too long; max key length is 767 bytes
出现这个问题是因为创建索引时指定的字段超过了存储引擎默认的长度。
MySQL 的每个单表中所创建的索引长度是有限制的,且对不同存储引擎下的表有不同的限制。
在 MySQL5.5 版本,引入了 innodb_large_prefix,用来禁用大型前缀索引,以便与不支持大索引键前缀的早期版本的 InnoDB 兼容
开启 innodb_large_prefix 可以使单索引的长度限制达到 3072 字节(但是联合索引总长度限制还是 3072 字节),禁用时单索引的长度限制为 767 字节
在 MySQL5.5版本与MySQL5.6 版本,innodb_large_prefix 是默认关闭的,在 MySQL5.7 及以上版本则默认开启
在 MySQL8.0 版本中,innodb_large_prefix 已被移除,从版本 8.0 开始,索引长度限制由表字段(row format)决定,
若为 DYNAMIC 或 COMPRESSED 时,限制值为 3072;为 REDUNDANT 或 COMPACT 时,限制值为 767。
为什么 3072:
InnoDB 一个 page 的默认大小是 16 k。由于是 Btree 组织,要求叶子节点上一个 page 至少包含两条记录(否则就退化链表了)。
所以一个记录最多不能超过 8 k。又由于 InnoDB 的聚簇索引结构,一个二级索引要包含主键索引,因此每个单个索引不能超过 4 k(极端情况,pk 和某个二级索引都达到这个限制)。
由于需要预留和辅助空间,扣掉后不能超过 3500,取个“整数”就是(1024 * 3 = 3072)。
utf8 与 utf8mb4 的区别:
由于历史原因,MySQL 刚开始设计的时候,"天真的"认为使用 3 个字节就足够存储字符串了,因此将 UTF-8 进行阉割;然而遇到复杂的汉字或者 emoji 表情等 4 字节的宽字符的时候,存储就会出现异常,
因此在版本 5.7.3 开始引入 utf8mb4,其表示为 most bytes 4,即最多占用 4 个字节。
utf8占用3个字节,utf8mb4占用4个字节,根据使用的存储引擎的不同,我们可以列出下面的表格。可以看到utf-8字符集的表使用INNODB存储引擎其索引字段的长度最大为256。
utf-8 | utf-8mb4 | |
---|---|---|
MYISAM | 1000/3=333 | 1000/4=250 |
INNODB | 768/3=256 | 768/4=192 |
回到我们出现的问题,我们添加索引的字段长度为255,如果是UTF-8字符集理论上是不超过索引长度限制的。但经过查看数据库表结构发现,此数据库表建表时使用了utf8mb4字符集。因此此时的长度限制应为192,。