MySQL 异常:max key length is 767 bytes

文若1年前技术文章472

前言

最近迁移几张表,又遇到 767 异常,迁移前只检查了 sql_mode 忽略对比了这个参数,导致几张表创建失败,其实解决方法也很简单,开启 innodb_large_prefix 参数重新导入即可。该 ERROR 常发生在字符串类型的大字段上,本篇文章简单记录下该问题。

42000 Specified key was too long; max key length is 767 bytes

1. 767 bytes 解读

如何知道某张表字符串字段占多少 bytes 呢?需要结合表的字符集来看:

CREATE TABLE `test_index` (
 `id` bigint(20) NOT NULL AUTO_INCREMENT,
 `name` varchar(800) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

上表的字符类型是 utf8 我们可以通过查表来判断字符最大可占用的空间:

show character set;

CharsetDescriptionDefault collationMaxlen
big5Big5 Traditional Chinesebig5_chinese_ci2
dec8DEC West Europeandec8_swedish_ci1
cp850DOS West Europeancp850_general_ci1
hp8HP West Europeanhp8_english_ci1
koi8rKOI8-R Relcom Russiankoi8r_general_ci1
latin1cp1252 West Europeanlatin1_swedish_ci1
latin2ISO 8859-2 Central Europeanlatin2_general_ci1
swe77bit Swedishswe7_swedish_ci1
asciiUS ASCIIascii_general_ci1
ujisEUC-JP Japaneseujis_japanese_ci3
sjisShift-JIS Japanesesjis_japanese_ci2
hebrewISO 8859-8 Hebrewhebrew_general_ci1
tis620TIS620 Thaitis620_thai_ci1
euckrEUC-KR Koreaneuckr_korean_ci2
koi8uKOI8-U Ukrainiankoi8u_general_ci1
gb2312GB2312 Simplified Chinesegb2312_chinese_ci2
greekISO 8859-7 Greekgreek_general_ci1
cp1250Windows Central Europeancp1250_general_ci1
gbkGBK Simplified Chinesegbk_chinese_ci2
latin5ISO 8859-9 Turkishlatin5_turkish_ci1
armscii8ARMSCII-8 Armenianarmscii8_general_ci1
utf8UTF-8 Unicodeutf8_general_ci3
ucs2UCS-2 Unicodeucs2_general_ci2
cp866DOS Russiancp866_general_ci1
keybcs2DOS Kamenicky Czech-Slovakkeybcs2_general_ci1
macceMac Central Europeanmacce_general_ci1
macromanMac West Europeanmacroman_general_ci1
cp852DOS Central Europeancp852_general_ci1
latin7ISO 8859-13 Balticlatin7_general_ci1
utf8mb4UTF-8 Unicodeutf8mb4_general_ci4
cp1251Windows Cyrilliccp1251_general_ci1
utf16UTF-16 Unicodeutf16_general_ci4
utf16leUTF-16LE Unicodeutf16le_general_ci4
cp1256Windows Arabiccp1256_general_ci1
cp1257Windows Balticcp1257_general_ci1
utf32UTF-32 Unicodeutf32_general_ci4
binaryBinary pseudo charsetbinary1
geostd8GEOSTD8 Georgiangeostd8_general_ci1
cp932SJIS for Windows Japanesecp932_japanese_ci2
eucjpmsUJIS for Windows Japaneseeucjpms_japanese_ci3
gb18030China National Standard GB18030gb18030_chinese_ci4

例如 utf8 的 Maxlen = 3 表示一个字符最大占用 3 bytes。那么 varchar 类型小于 255 字符,就不会触发 767 异常。

2. 异常原因

为什么会有这个异常呢?其实该异常属于 MySQL Innodb 引擎的限制,例如一张表最多有 1017 个字段,一张表最大有 64 个二级索引一样,如果索引列的字符长度很大的话,二级索引占用的空间也会非常大,一个页面存储的索引字段减少,索引深度会更容易变深,增加 IO 次数,搜索的性能也不会理想。

If innodb_large_prefix is enabled (the default), the index key prefix limit is 3072 bytes for InnoDB tables that use the DYNAMIC or COMPRESSED row format. If innodb_large_prefix is disabled, the index key prefix limit is 767 bytes for tables of any row format.

Innodb 引擎的限制:14.23 InnoDB Limits  

3. 5.7 和 8.0 版本的区别

在 5.7 版本中,对于使用 DYNAMIC 或 COMPRESSED 行格式的 InnoDB 表,索引前缀的限制为 767 bytes,如果开启 innodb_large_prefix 参数,限制阈值上调为 3072 bytes。

在 8.0 版本中,参数 innodb_large_prefix 被删除,索引前缀最大为 3072 bytes 不再有 767 bytes 的限制。

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


相关文章

oracle安装gi执行root.sh报错:PRCR-1079 : Failed to start resource ora.cvu

1、具体报错如下:安装gi执行root.sh报错:PRCC-1014 : LISTENER_SCAN1 was already runningPRCR-1004 : Resource ora.LIST...

Docker 网络介绍

一、Docker 网络docker网络主要是解决容器联网问题,也是我们使用容器中最重要的一个环节,如果容器没有网络则无法向网络中提供服务。网络管理命令:docker network[root@zutu...

大数据集群监控配置操作指导(一)prometheus+grafana部署

大数据集群监控配置操作指导(一)prometheus+grafana部署

1.prometheus+grafana部署(单独部署到一台服务器。4c8g。系统盘300G。操作系统建议7.6到7.9)1.1下载prometheus和grafana的二进制包mkdir /opt/...

k8s Krew 插件使用指南

kubectl Krew 插件使用指南前言:在某些情况下,只是使用 kubectl 命令的时候存在效率比较低、功能不满足的问题,针对这些问题,社区提出了krew插件项目。还有一点是:大部分工程师还是喜...

MySQL性能优化(三)函数运算导致无法使用索引

MySQL性能优化(三)函数运算导致无法使用索引

有时侯我们会遇到这样的情况:明明字段上已经建立了索引,但是查询还是无法使用索引。其中有一种情况是因为SQL中对索引字段进行了运算。一个例子select * from us...

haproxy服务无法正常启动

haproxy服务无法正常启动

【局点信息】测试环境【集群信息】【问题现象】haproxy设置配置文件后,无法正常启动,查看服务状态显示失败配置增加内容#增加如下配置 listen ApiApplicationServer   ...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。