最佳前缀长度需基于真实数据区分度确定,即通过sql计算count(distinct left(email,n))/count(*)并逼近全字段选择性,优先选取区分度跃升拐点且体积增幅最小的n值。

前缀索引长度不是拍脑袋定的,必须基于真实数据分布计算;选短了查得慢,选长了白占空间,关键在“选择性拐点”。
怎么算出 email 字段的最佳前缀长度
直接跑 SQL 查不同长度下的唯一值比例,比凭经验猜可靠得多。目标是让 COUNT(DISTINCT LEFT(email, N)) / COUNT(*) 尽量接近全字段的选择性(即 COUNT(DISTINCT email) / COUNT(*)),但又不盲目拉长。
- 先看全字段基准值:
SELECT COUNT(DISTINCT email)/COUNT(*) AS total_sel FROM users; - 再横向对比几个候选长度:
SELECT COUNT(DISTINCT LEFT(email, 6))/COUNT(*) AS sel6, COUNT(DISTINCT LEFT(email, 7))/COUNT(*) AS sel7, COUNT(DISTINCT LEFT(email, 8))/COUNT(*) AS sel8 FROM users; - 如果
sel7是 0.982、sel8是 0.983,提升仅 0.001,而索引体积多占约 15%,那 7 就是更优解
为什么 LENGTH=10 的前缀索引对 LIKE 'xxx%' 有效,但对 ORDER BY email 失效
前缀索引只存前 N 个字符,MySQL 没法靠它还原完整字符串顺序,所以排序、分组、覆盖索引都用不了。
-
WHERE email LIKE 'admin%'→ 能走前缀索引(最左前缀匹配) -
ORDER BY email→ 必须回表取完整值再排序,无法利用索引有序性 -
SELECT email FROM users WHERE email LIKE 'test%'→ 仍要回表,因为索引里没存全量email,不能覆盖查询 - 中文字段注意:utf8mb4 下一个汉字占 4 字节,
email(10)实际可能只截到 2–3 个汉字,需按字节而非字符数预估
什么时候不该用前缀索引
不是所有长字符串都适合——如果前缀重复度高,或者查询模式不匹配最左前缀,建了也白建。
- URL 字段以
https://开头居多,前 8 个字符几乎全一样 →LEFT(url, 8)选择性极低,别硬上 - 查询经常用
WHERE email REGEXP '.+@gmail\.com$'或LIKE '%@qq.com'→ 前缀索引完全无效 - 字段本身基数低(比如只有几十个固定邮箱域名),直接建哈希索引或枚举化更合适
-
TEXT或BLOB类型强制要求指定前缀长度,但若业务真需要全文模糊匹配,应考虑FULLTEXT索引或外部搜索引擎
真正容易被忽略的是数据漂移:今天选的长度在半年后可能失效。用户注册邮箱域名集中度变化、爬虫注入大量相似测试邮箱,都会拉低选择性。上线后得定期用相同 SQL 复检 selN 值,而不是建完就扔。











