前缀索引通过在varchar/text字段列名后加括号指定字符长度实现,如index idx_name (name(10));不支持函数表达式、单位为字符数、仅适用于字符串类型,需权衡区分度与查询覆盖性。

MySQL前缀索引怎么写:在CREATE INDEX或ALTER TABLE里指定长度
直接说结论:前缀索引就是在定义索引时,对VARCHAR、TEXT这类变长字段,只索引其前N个字符,语法就是在列名后加(length)。比如INDEX idx_name (name(10))表示只索引name字段的前10个字符。
常见错误是写成INDEX idx_name (SUBSTR(name, 1, 10))——MySQL不支持表达式索引(8.0.13之前),也不能用函数包装;还有人误以为(10)是字节数,其实单位是字符数(utf8mb4下1个中文=1字符)。
- 必须是字符串类型字段,
INT、DATETIME等不支持加长度 - 长度值不能超过字段定义的最大长度(如
VARCHAR(255)最多写(255)) - 建表时写在
CREATE TABLE语句的INDEX子句里;已有表用ALTER TABLE ADD INDEX
什么时候该用前缀索引:查SHOW INDEX和SELECT COUNT(DISTINCT)来判断
不是所有字符串字段都适合加前缀索引。核心看两点:区分度是否足够高、前缀是否能覆盖绝大多数查询条件。
比如用户邮箱字段email VARCHAR(255),如果大量邮箱以gmail.com结尾,那取前5位(如user@)可能重复极高,索引失效;但取前12位(含用户名+@+域名前段)就可能够用。
- 先跑
SELECT COUNT(DISTINCT LEFT(email, 10)) / COUNT(*) FROM users;,结果越接近1越好(比如>0.95) - 再对比不同长度下的区分度:
SELECT COUNT(DISTINCT LEFT(email, 8)), COUNT(DISTINCT LEFT(email, 12)), COUNT(DISTINCT email) FROM users; - 用
SHOW INDEX FROM users WHERE Key_name = 'idx_email';确认实际生效长度是否和你写的匹配
ALTER TABLE ... ADD INDEX加前缀索引的实操写法
已有表加前缀索引最常用,语法干净,但要注意锁表现象(尤其大表)。
示例:给articles表的title字段加前20字符索引:
ALTER TABLE articles ADD INDEX idx_title_prefix (title(20));
- 如果字段是
TEXT类型,必须加长度,否则报错ERROR 1170 (42000): BLOB/TEXT column 'title' used in key specification without a key length - 执行期间会加MDL锁,线上大表建议在低峰期操作,或用
ALGORITHM=INPLACE(5.6+支持,但非所有情况都可用) - 别名索引名(如
idx_title_prefix)最好体现“前缀”含义,避免和未来全字段索引冲突
前缀索引的坑:ORDER BY、GROUP BY和覆盖索引失效
前缀索引只存前N字符,所以它无法支撑需要完整字段值的场景。
典型问题:即使你写了SELECT title FROM articles WHERE title LIKE 'MySQL%'能走索引,但SELECT title FROM articles ORDER BY title LIMIT 10很可能退化为filesort——因为索引里没有完整title,MySQL无法靠索引完成排序。
-
GROUP BY title同理,可能无法利用前缀索引做分组优化 - 无法用于覆盖索引:
SELECT title FROM ... WHERE title LIKE 'xxx%'可以,但SELECT title, content FROM ...不行,因为title字段值不完整,仍需回表 - 如果业务强依赖排序或去重,宁可加更长前缀(如30~50),或改用生成列+函数索引(MySQL 8.0.13+)
真正麻烦的是区分度波动——用户昵称字段,早期都是“用户123”,后来变成“张三_摄影”,前缀长度得跟着调,没人盯就容易慢慢失效。











