like 'keyword%' 能走索引是因为b+树按字典序存储,可利用最左前缀匹配快速定位起始位置;而'%keyword'无固定开头,无法跳转,只能全表扫描,explain显示type=all、key=null。

LIKE 'keyword%' 为什么能走索引而 '%keyword' 不能
MySQL 的 B+ 树索引是按字典序存储的,所以只有当匹配模式是「确定前缀」时,才能利用索引快速定位起始位置。比如 username LIKE 'admin%',数据库可以直接跳到以 admin 开头的所有索引项;但 username LIKE '%min' 没有固定开头,只能逐条扫描,索引完全失效。
常见错误现象:用 EXPLAIN 看到 type 是 ALL,key 为 NULL,说明走了全表扫描。
- 索引只对
LIKE 'xxx%'有效,LIKE '%xxx'和LIKE '%xxx%'都无法使用常规 B-TREE 索引 - 如果字段很长(如
VARCHAR(255)),建普通索引开销大、效果差,应考虑前缀索引 - 前缀索引长度不是越长越好:过长浪费空间,过短容易重复;可用
SELECT COUNT(DISTINCT LEFT(username, N)) / COUNT(*) FROM users;测试区分度,建议选择区分度 > 0.9 的 N
前缀索引怎么建才不踩坑
前缀索引不是简单加个 INDEX 就完事。它只保留字段前 N 个字符,后续字符被截断,所以对 LIKE 'xxx%' 有效,但对 LIKE '%xxx' 或全文内容判断无效。
实操建议:
- 建索引语句写成:
CREATE INDEX idx_username_prefix ON users (username(10));,其中10是前缀长度,不是字节数(utf8mb4 下中文占 4 字节,需注意) - 避免在
WHERE中对字段做函数操作,例如LOWER(username) LIKE 'admin%'会让前缀索引失效——应改用生成列 + 索引,或插入时统一小写存储 - 联合索引中若含前缀字段,要确保它在最左位置,否则无法命中,例如
(status, username(10))无法用于WHERE username LIKE 'a%'
FULLTEXT 全文索引适合什么场景
全文索引不是给所有模糊查询兜底的银弹。它只适用于自然语言搜索(如文章标题、描述字段),且要求字段类型是 CHAR/VARCHAR/TEXT,引擎为 InnoDB 或 MyISAM。
典型误用:
- 拿全文索引查手机号、用户名、订单号这类结构化短字符串——词法分析无意义,反而更慢
- 用
LIKE写法混搭全文索引,例如WHERE MATCH(title) AGAINST('MySQL') AND title LIKE '%optim%',后半部分仍可能拖垮性能 - 未配置最小/最大词长(
ft_min_word_len默认 4),导致搜“id”“to”等短词失败,却没意识到是配置问题
正确姿势是单独使用:SELECT * FROM articles WHERE MATCH(title, content) AGAINST('performance optimization' IN NATURAL LANGUAGE MODE);
INSTR/LOCATE 能替代 LIKE 吗
不能提升性能,只是换种写法。大量实测(含 200w+ 数据集)表明:INSTR(field, 'kw') > 0 和 field LIKE '%kw%' 在执行计划、耗时、IO 上几乎一致,都走全表扫描。
它们唯一价值是绕过某些 ORM 对 LIKE 的语法限制,或配合生成列做函数索引(MySQL 5.7+):
ALTER TABLE users ADD COLUMN username_lower VARCHAR(50) STORED AS (LOWER(username));CREATE INDEX idx_un_lower ON users (username_lower);- 再查
WHERE username_lower LIKE 'admin%'就能走索引
真正卡顿的点往往不在函数选型,而在没意识到:百万级数据下,LIKE '%xxx%' 类查询本就不该直接扛在主库上——要么前置缓存,要么导出到 Elasticsearch,要么用分词+倒排,而不是死磕 MySQL 函数。











