MySQL 异常:max key length is 767 bytes

前言

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

[42000][1071] 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

4. 版本 5.6 特殊情况

在 5.6 版本中 innodb_default_row_format = Compact 默认值,只有 DYNAMIC 和 COMPRESSED 行格式突破 767,所以 5.6 版本修改参数后,依然无法创建大于 767 字节的索引,此时可以去查表的行格式,大概率是行格式不支持:

select TABLE_SCHEMA, TABLE_NAME, ROW_FORMAT
from information_schema.TABLES where TABLE_NAME = '表名'

此时修改行格式可以解决:

alter table 表名 row_format=dynamic;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值