前缀索引适用于字段值长且前缀选择性高(≥0.95)的场景,可显著减小索引体积;但不支持完整等值匹配、排序及后缀模糊查询;需避免长度过短、过长或字节截断问题,优先考虑哈希列、生成列等替代方案。

前缀索引适合字段值很长且前缀区分度高的场景
当 VARCHAR 字段(如邮箱、URL、标题)长度动辄 200+,但实际前 10–30 个字符就足以唯一或高度区分时,前缀索引能显著减少索引体积。比如 email 字段平均长度 80,但前 30 位的重复率低于 0.01%,这时建 INDEX idx_email ON users(email(30)) 就比全字段索引节省近 60% 的 B+ 树空间。
关键判断依据不是“字段长”,而是前缀的选择性(COUNT(DISTINCT LEFT(col, N)) / COUNT(*)),建议该值 ≥ 0.95 再考虑前缀索引。
不适用于需要完整值匹配或排序的查询
前缀索引只保存和比较前 N 个字符,因此以下操作会失效或退化:
-
WHERE email = 'a@b.com'—— 无法使用前缀索引做等值精确匹配(除非 N 足够覆盖整个值,但这就失去前缀意义) -
ORDER BY email DESC—— MySQL 无法用前缀索引完成完整排序,会触发 filesort -
SELECT email FROM users WHERE email LIKE '%@gmail.com'—— 后缀模糊查,前缀索引完全无效
这类场景必须用全文索引、生成列索引,或接受全字段索引的空间成本。
创建前缀索引要避免常见长度陷阱
选错前缀长度会导致性能反降或空间浪费:
- 太短(如
name(2)):中文姓名前 2 字重复极高,选择性差,索引几乎无效 - 太长(如
url(255)):接近原字段长度,B+ 树节点变大,单页存的键值变少,树高增加,反而降低查询效率 - 未对齐字符边界(尤其 UTF8MB4):MySQL 按字节截取,
name(10)可能截断一个 3 字节汉字,导致索引值损坏;应结合CHAR_LENGTH()和LENGTH()验证实际字节数
实操建议:先用 SELECT COUNT(DISTINCT LEFT(url, 32)) / COUNT(*) AS sel FROM pages; 测选择性,再逐步试 32→48→64,直到选择性达标且 SHOW INDEX 中的 Sub_part 列不再明显提升查询命中率。
替代方案比盲目加前缀索引更值得优先评估
前缀索引是权衡妥协,不是银弹。遇到长字段索引膨胀,优先检查这些更干净的解法:
- 拆出确定性哈希列:
ALTER TABLE logs ADD COLUMN url_sha1 CHAR(40) AS (SHA1(url)) STORED;
然后对url_sha1建普通索引,等值查极快且固定长度 - 用生成列 + 函数索引(MySQL 8.0.13+):
ALTER TABLE docs ADD COLUMN title_prefix VARCHAR(50) AS (LEFT(title, 50)) STORED;
再建INDEX idx_title_prefix ON docs(title_prefix) - 业务层控制输入长度(如 URL 截断到 200 字符并校验唯一性),从源头减小索引压力
真正容易被忽略的是:前缀索引无法被 EXPLAIN 中的 key_len 准确反映真实比较逻辑——它只显示定义长度,不体现实际区分效果。线上观察必须结合 Handler_read_key 和慢查中的 rows_examined 综合判断是否真的生效。










