因innodb索引长度按字符集最大字节宽预估,utf8mb4每字符占4字节,varchar(255)达1020字节,超旧版767字节限制;新版本3072字节上限下最多支持varchar(768),联合索引需累加各字段字节总和。

utf8mb4字段建索引时为什么报“Specified key was too long”
因为InnoDB对单字段索引长度有硬性字节上限(老版本767字节,新版本默认3072字节),而utf8mb4按最坏情况——每个字符占4字节来计算索引长度。比如定义VARCHAR(255)并加索引,在utf8mb4下理论最大索引长度是255 × 4 = 1020字节,直接超出旧版767限制。
- MySQL 5.7.6及更早:单字段索引上限为767字节 →
utf8mb4字段最多支持VARCHAR(191)(191 × 4 = 764 ≤ 767) - MySQL 5.7.7+且
innodb_large_prefix=ON(默认):上限升至3072字节 → 最多支持VARCHAR(768)(768 × 4 = 3072) - 联合索引要按所有字段字节总和算,容易更快触顶;例如两个
VARCHAR(200)字段合起来就是1600字节,超限
为什么MySQL不按实际存储字节数算索引长度,而按最大可能字节数?
索引结构在创建时就要预留空间,InnoDB必须为每个字符预留最大编码宽度,否则无法保证B+树节点分裂、比较、排序的稳定性。它不扫描实际数据内容,只看字段定义和字符集声明。
-
utf8(实为utf8mb3)按3字节/字符算 →VARCHAR(255)索引长765字节,刚好卡在767边界内 -
utf8mb4按4字节/字符算 → 同样VARCHAR(255)就变成1020字节,必然超限 - 即使字段里全是ASCII字符(1字节),只要定义是
utf8mb4,索引长度仍按4字节/字符预估
如何快速判断一个字段能否加索引而不超限
用这个公式手动验算:字段定义长度 × 每字符最大字节数 ≤ 当前引擎允许的最大索引字节数。别依赖直觉,尤其别照搬utf8下的经验直接套用到utf8mb4。
- 查当前限制:
SHOW VARIABLES LIKE 'innodb_large_prefix';+ 查MySQL版本 - 查字符集每字符最大字节数:
utf8mb4是4,utf8是3,latin1是1 - 常见踩坑:给
title VARCHAR(255) CHARSET utf8mb4直接CREATE INDEX idx_title ON t(title);→ 旧版本必报错 - 安全做法:对需索引的
utf8mb4文本字段,优先设为VARCHAR(191)(兼容所有版本)或VARCHAR(768)(仅限5.7.7+且确认innodb_large_prefix=ON)
排序规则(collation)会影响索引长度计算吗
不影响字节长度计算本身,但影响索引行为和实际性能。例如utf8mb4_0900_ai_ci比utf8mb4_bin在字符串比较时更耗CPU,但它不改变每个字符占多少字节——索引长度只取决于字符集,和collation无关。
- 错误认知:“换用
utf8mb4_bin就能绕过索引长度限制” → 不成立,仍是4字节/字符 - 真正相关的是
collation是否支持生成前缀索引(如INDEX(title(100))),但这只是折中方案,不是解除限制 - 若业务允许模糊搜索,可考虑
FULLTEXT索引替代常规B+树索引,避开长度限制问题
VARCHAR(191)没问题,但三个合起来就可能突破3072字节上限,尤其在MySQL 5.7.7+环境下。别只盯着单字段,得把整个KEY定义拉出来逐字节算。











