LIKE '%xxx' 一定不走索引,因B+树仅支持左前缀匹配,前导%使MySQL无法定位索引页,只能全表扫描(type=ALL);可用REVERSE()+函数索引优化后缀匹配,或FULLTEXT索引支持任意位置关键词搜索。

LIKE '%xxx' 为什么一定不走索引
因为 B+ 树索引按字段完整值排序,只支持从左开始的匹配。% 出现在开头时,MySQL 无法预判哪些索引页可能含目标子串,只能逐行扫描整张表——EXPLAIN 中 type 显示为 ALL 就是铁证。这不是写法问题,也不是统计信息不准,而是索引结构本身的限制。
用 reverse() + 函数索引解决后缀匹配
MySQL 8.0+ 支持函数索引,这是唯一能真正让 LIKE '%xxx' 走索引的原生方案,但仅适用于后缀场景(如查“有限公司”“.com”)。
- 添加函数索引:
ALTER TABLE users ADD INDEX idx_username_rev ((REVERSE(username))); - 查询必须改写为:
SELECT * FROM users WHERE REVERSE(username) LIKE REVERSE('%admin'); - 不能写成
REVERSE(username) LIKE '%nimda'——否则又变成前导 %,索引失效 - 该方案对存储无额外开销(不存新列),但要求应用层统一改 SQL,且不适用于
LIKE '%xxx%'
FULLTEXT 索引更适合任意位置关键词搜索
如果业务需要查 LIKE '%数据库优化%' 这类中间模糊,FULLTEXT 是比硬扛 B+ 树更现实的选择,底层用倒排索引,不依赖字符位置。
- 建索引:
ALTER TABLE articles ADD FULLTEXT (title, content); - 查法:
SELECT * FROM articles WHERE MATCH(title, content) AGAINST('数据库优化' IN NATURAL LANGUAGE MODE); - 中文需配
ngram分词器:ALTER TABLE articles ADD FULLTEXT (title) WITH PARSER ngram; -
innodb_ft_min_token_size默认为 4,搜“AI”“李”会被忽略,上线前必须验证分词效果
别用 LOCATE / INSTR 替代 LIKE
很多人试 LOCATE('xxx', field) > 0 或 INSTR(field, 'xxx') > 0,以为能绕过 LIKE 限制——实测在百万级数据上,执行计划仍是 type: ALL,性能毫无改善,反而增加 CPU 计算负担。
- 这些函数只是把字符串匹配逻辑从优化器移到了存储引擎层,没改变全表扫描本质
- 字段越长、匹配越靠后,CPU 开销越大
- 它们和
LIKE '%xxx%'在执行层面是等价的,别抱侥幸心理
实际落地时最容易被忽略的是:函数索引方案里 REVERSE('%xxx') 的写法必须严格一致,漏掉一个括号或顺序错位,索引就彻底失效;FULLTEXT 则常因未启用 ngram 或未调小 innodb_ft_min_token_size 导致中文短词查不到——这些细节不验证,优化就等于白做。


















