like查询慢主因是索引未被使用,尤其是like '%xxx'或like '%xxx%'无法利用b+树索引;优化方向为改用reverse()函数索引(mysql 8.0+)解决后缀匹配,或用fulltext索引处理任意位置关键词搜索。

LIKE 查询慢,绝大多数时候不是 SQL 写得不够“巧”,而是索引根本没被用上——尤其是 like '%xxx' 或 like '%xxx%' 这类写法,MySQL 默认放弃索引走全表扫描。优化方向很明确:要么让查询能走索引,要么换更合适的搜索机制。
为什么 like '%xxx' 一定不走索引?
B+ 树索引按字段完整值排序,只支持“从左开始”的匹配。当通配符 % 出现在开头,MySQL 无法预判哪些叶子节点可能含目标子串,只能逐行扫描。
-
like 'xxx%'→ 可走索引(范围扫描) -
like '%xxx'或like '%xxx%'→ 索引失效(type: all) -
like 'xx%x'(中间有%)→ 同样失效,只要开头不是固定字符串,B+ 树就无能为力
用 reverse() + 函数索引解决后缀匹配
MySQL 8.0+ 支持函数索引,这是破解 like '%xxx' 的最直接办法:把字段反转,再对反转结果建索引,查询时也反转模式。
- 添加反转列并建索引:
alter table users add index idx_username_rev ((reverse(username))); - 改写查询:
select * from users where reverse(username) like reverse('%admin'); - 注意:必须用
reverse('%admin'),不能写成reverse(username) like '%nimda'—— 否则又变成前导%,索引仍失效 - 该方案对存储空间影响小,但需应用层配合改写 SQL,且仅适用于后缀匹配场景
全文索引更适合含关键词的任意位置匹配
如果业务需要查 like '%关键词%',且字段内容是自然语言(如文章标题、描述),fulltext 索引比 B+ 树更合适,底层用倒排索引,不依赖字符位置。
- 建索引:
alter table articles add fulltext (title, content); - 查法:
select * from articles where match(title, content) against('数据库优化' in natural language mode); - 中文需额外处理:InnoDB 的
innodb_ft_min_token_size默认为 2,短词(如“AI”)可能被忽略;实际项目中常搭配分词插件或 ES 做前置处理 - 不支持
like那种模糊通配,但支持布尔模式(+mysql -oracle)、相关度排序,语义更丰富
别碰 locate()、instr() 这类函数来“替代” LIKE
很多人试过用 locate('xxx', field) > 0 或 instr(field, 'xxx') > 0 替代 like '%xxx%',实测在百万级以上数据中,性能几乎没差别——它们一样无法走索引,执行计划仍是 type: all。
- 这些函数只是把匹配逻辑从优化器移到了存储引擎层,没改变全表扫描本质
- 反而增加 CPU 计算开销,尤其字段较长时,每个值都要做子串查找
- 真正有效的优化永远围绕“能否走索引”或“是否该换技术栈”展开,而不是在函数之间反复横跳
最容易被忽略的一点:没有银弹。前缀匹配用普通索引,后缀匹配用 reverse() 函数索引,任意位置关键词匹配优先考虑 fulltext 或外置搜索引擎。选错路径,调参和重写 SQL 都只是在给瓶颈打补丁。











