前缀索引长度应通过计算前n字符的区分度(如select count(distinct left(col,n))/count(*)>0.95)确定,避免盲目设长;仅varchar支持前缀索引,char不支持;仅左前缀匹配查询(如like 'abc%')生效,右模糊、下划线通配、order by等场景失效;utf8mb4下需按字节数(非字符数)评估索引长度是否超限。

前缀索引该建多长才不丢区分度
前缀索引长度不是拍脑袋定的,核心是看字段值前 N 个字符的重复率。比如 email 字段,前 5 位可能是 user、admin、test,区分度低;但前 12 位大概率已唯一。直接查重复率最靠谱:
SELECT COUNT(DISTINCT LEFT(email, 10)) / COUNT(*) AS selectivity FROM users;
一般要求 selectivity > 0.95(95%以上值能被区分)。低于这个数就加长度,再试 11、12……直到达标。别盲目设到 20 —— 多余长度只占空间、不提性能。
CHAR/VARCHAR 字段建前缀索引的语法陷阱
MySQL 允许对 VARCHAR 建前缀索引,但不支持对 CHAR 字段用前缀长度(会报错 ERROR 1071 (42000): Specified key was too long 或隐式截断)。正确写法只有这一种:
ALTER TABLE users ADD INDEX idx_email_prefix (email(15));
注意:email(15) 是合法的,email CHAR(100) 却不能写成 email(15) —— MySQL 会把它当完整字段处理,导致索引键超长。实际中建议把固定长度但内容短的字段(如身份证号)改用 VARCHAR 再建前缀索引。
前缀索引失效的常见查询场景
前缀索引只加速「从左开始匹配」的查询,以下情况它完全不生效:
-
WHERE email LIKE '%@gmail.com'(右模糊,无法用前缀) -
WHERE email LIKE '_a%'(下划线通配首字符,B+Tree 找不到起点) -
ORDER BY email DESC配合LIMIT分页(前缀索引不存完整值,排序可能不准) -
SELECT email FROM users WHERE email LIKE 'abc%'能走索引,但SELECT *仍要回表——如果业务常查整列,得权衡是否值得省这点 B+Tree 空间
UTF8MB4 下长度计算必须按字节数算
MySQL 的前缀长度单位是「字符数」,但 utf8mb4 下一个汉字/emoji 占 4 字节。InnoDB 页面大小固定(默认 16KB),单个索引记录不能超 767 字节(或开启 innodb_large_prefix 后 3072 字节)。所以建索引前得算清:
假设字段定义是 VARCHAR(200) CHARSET utf8mb4,你设 email(100),最坏情况(全 emoji)占 400 字节,安全;但设 email(800) 就爆了——即使字符数没超 200,字节数也远超限制。
真正保险的做法是:先用 LENGTH() 看样本数据实际字节分布,再反推安全前缀长度。线上表加索引前,务必在测试库跑 SHOW WARNINGS 确认没隐式截断。
前缀索引省的是 B+Tree 叶子节点的存储,但代价是丧失完整值语义。很多团队踩坑在于只测了「建得上」,没验证「查得对」——尤其是涉及排序、去重、导出全量值的逻辑。











