前缀索引是对字符串列前n字符建的真实索引,仅支持left()类最左前缀匹配查询,不支持like '%...'、order by等;需通过区分度评估选最优长度,创建时用email(n)语法并验证sub_part值。

前缀索引不是“缩略版索引”,而是对 VARCHAR、TEXT 这类字符串列的前 N 个字符建立真实索引——MySQL 在查询时能用它加速,但代价是放弃完整值的语义能力。
前缀索引只支持 LEFT() 类型的匹配
它本质上依赖最左前缀原则:只有 WHERE column LIKE 'abc%' 或 WHERE column = 'abcdefg' 这类能利用前缀比较的查询才生效;LIKE '%xyz'、LIKE '%abc%'、ORDER BY column、GROUP BY column 全部无法使用该索引。
- 即使你建了
email(10),WHERE email LIKE 'test%@example.com'也走不了索引(因为通配符在开头) -
WHERE email = 'a@b.c'能用,但前提是实际值前 10 字符和索引键完全一致;如果值短于 10,MySQL 会自动补空格再比(注意CHAR和VARCHAR行为差异) - 不能用于覆盖索引:执行
SELECT email FROM users WHERE email LIKE 'foo%'仍需回表查完整字段值
怎么算出靠谱的前缀长度
目标不是“越长越好”,而是找到区分度接近全列、但又尽可能短的那个点。直接跑这条 SQL:
SELECT COUNT(DISTINCT LEFT(email, 5)) / COUNT(*) AS p5, COUNT(DISTINCT LEFT(email, 6)) / COUNT(*) AS p6, COUNT(DISTINCT LEFT(email, 7)) / COUNT(*) AS p7, COUNT(DISTINCT LEFT(email, 8)) / COUNT(*) AS p8, COUNT(DISTINCT email) / COUNT(*) AS full_sel FROM users;
观察输出:如果 p7 是 0.942,full_sel 是 0.945,那 7 就是合理候选;若 p6 才 0.82,说明 6 不够,必须加长。
- 别只看单点,要横向对比——从 4 开始试到 12,画个简易表格更直观
- 线上表数据分布可能倾斜,建议在采样 10–20% 数据上先试,避免全表扫描拖慢评估
- 如果
full_sel本身低于 0.8(比如邮箱列有大量重复或测试数据),前缀索引意义不大,优先查业务是否允许去重或改结构
创建和验证前缀索引的实操细节
语法很简单,但几个地方容易翻车:
- 用
CREATE INDEX idx_user_email ON users (email(10)),不是email[10]或email[0:10]——括号里只能是纯数字 - 建完立刻执行
SHOW INDEX FROM users,确认Sub_part列显示10,而不是NULL(NULL表示建的是完整索引) - 联合索引里也能用前缀,比如
(status, email(8), created_at),但注意:只有status+email前 8 位都匹配时,这部分才生效 - 前缀长度受字符集影响:UTF8MB4 下一个汉字占 4 字节,
email(10)实际最多存 10 字节,不一定是 10 个字符(不过对邮箱、URL 这类 ASCII 主导字段影响小)
真正难的不是建索引,而是判断“值不值得建”——当字段前 3 位全是 http 或 china,或者大量值以相同前缀开头时,再长的前缀也救不了选择性。这种时候,与其硬调长度,不如先看数据分布、查查是否该拆字段或加业务约束。











