前缀索引适合字段值很长且前缀区分度高的场景
当
VARCHAR字段(如邮箱、URL、标题)长度动辄 200+,但实际前 10–30 个字符就足以唯一或高度区分时,前缀索引能显著减少索引体积。比如
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综合判断是否真的生效。
