前缀索引无法支撑范围查询、排序、分组,且等值查询易因前缀冲突失效;仅适用于高区分度字段的等值前缀匹配场景。

前缀索引无法支撑范围查询的起始定位
前缀索引只存储字段值的前 N 个字符(如 INDEX idx_name (name(10))),它本质上是截断后的有序序列。B+树索引生效的前提是:优化器能根据查询条件精确推导出扫描的起始页和终止页。但当你执行 WHERE name >= 'abc' 时,真实值可能是 'abcdef' 或 'abccxyz',而前缀索引中只存了 'abc' —— 所有以 'abc' 开头的原始值在前缀索引里都“坍缩”成同一个键,破坏了原始值的全序关系。优化器无法据此确定 B+ 树中哪些叶子节点需要访问,只能退回到全索引扫描或全表扫描。
前缀长度不足时等值查询也会失效
前缀索引的等值匹配依赖“前缀唯一性”。如果两个不同值的前 N 位完全相同(例如 'apple' 和 'application' 在 name(5) 下都是 'apple'),那么 WHERE name = 'apple' 就无法靠前缀索引精确定位——MySQL 必须回表逐行比对完整值,此时优化器可能直接放弃该索引,尤其当重复前缀比例高、回表成本大时。
- 用
SELECT COUNT(DISTINCT LEFT(name, 10)) / COUNT(*) FROM t;估算前缀选择性,低于 0.95 就要警惕 - 前缀越短,冲突概率越高;但过长又失去节省空间的意义,需权衡
EXPLAIN 中 key_len 异常小且 type=ref 但 rows 偏大
这是前缀索引实际生效却效率低下的典型信号。比如联合索引 (status, name(8), created_at),执行 WHERE status = 1 AND name = 'johnny',EXPLAIN 显示 key_len: 11(status 占 1 字节 + name 前缀占 10 字节),看似走了索引,但 rows 高达数万——说明前缀区分度差,大量数据被拉到二级索引叶子节点,再逐个回表校验完整 name 值。这种“伪走索引”比全表扫描更耗 IO。
- 不要只看
key是否非 NULL,重点盯key_len和rows的组合 -
Extra: Using index condition出现时,说明 MySQL 正在用 ICP(索引条件下推)过滤前缀后剩余的行,但这不改变前缀本身的选择性缺陷
前缀索引无法用于排序和分组
ORDER BY 和 GROUP BY 要求索引列的值具备全序性或可聚合性。前缀索引只保留片段,ORDER BY name 无法保证结果按完整字符串字典序排列——'abc' 可能对应 'abcde' 或 'abcf',二者在完整字符串中顺序不同,但在前缀索引里无从区分。MySQL 检测到这一点后会放弃使用该索引做排序,改用 filesort。
- 若业务强依赖
ORDER BY name,宁可建完整列索引,或用覆盖索引 + 应用层排序 -
GROUP BY name同理:前缀相同但原值不同的记录会被错误归为一组
email_domain VARCHAR(64) 上建 INDEX idx_domain (email_domain(20)),因为 '@gmail.com'、'@qq.com' 等天然前缀差异大。一旦涉及范围、排序、分组或低区分度字段,它的“节省空间”优势立刻被查询代价反噬。











