LIKE '%xxx' 一定不走索引,因为B+树索引需左前缀确定性,以%开头无法定位查找起点;函数、隐式转换、前缀索引等也常导致索引失效。

LIKE 查询不走索引,绝大多数时候不是 SQL 写得不够“巧”,而是根本没满足 B+ 树索引的匹配前提——它只认「左前缀可确定性」。只要 LIKE 模式以 % 开头(比如 '%abc' 或 '%abc%'),type 几乎必为 ALL,key 为 NULL。
为什么 LIKE '%xxx' 一定不走索引
B+ 树索引是按字段完整值字典序排好的线性结构,查找必须能定位一个明确起点。比如 LIKE 'abc%' 可转成 name >= 'abc' AND name ,优化器能快速跳到第一个 <code>'abc' 开头的位置;但 '%abc' 没有起点,MySQL 必须逐行取值、截取末尾再比对,等于放弃索引做全表扫描。
常见误判点:
- 给
(status, name)建联合索引,却查WHERE name LIKE '%abc'→name在索引中完全不可用 - 用
REGEXP 'abc$'替代 → 同样不走索引,正则和LIKE在索引友好度上没区别 - 字段是
utf8mb4_0900_as_cs,但查询字面量没声明 collation → 触发隐式转换,EXPLAIN显示用了索引,实际性能接近全表扫描
MySQL 8.0+ 用 reverse() + 函数索引解后缀匹配
这是唯一能真正让 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') - 确认生效:
EXPLAIN中type应为range或ref,key显示idx_username_rev
限制很明确:只适用于固定后缀场景(如查邮箱域名 '%@gmail.com'、文件扩展名 '%.pdf'),且需应用层配合改 SQL。
MySQL 数据库管理技能,能够通过自然语言查询和管理数据库,支持 SELECT/INSERT/UPDATE/DELETE、表管理、备份恢复等操作。当用户提及 MySQL、数据库查询、建表或数据备份时使用此技能。
全文索引替代 LIKE '%xxx%' 的实操要点
当业务真要支持任意位置关键词搜索(比如文章标题含“数据库优化”),FULLTEXT 是比硬扛 LIKE 更现实的选择。
关键条件与配置:
- 存储引擎必须是 InnoDB,MySQL ≥ 5.6
- 建索引:
ALTER TABLE articles ADD FULLTEXT (title, content);(仅支持CHAR/VARCHAR/TEXT) - 必须用
MATCH() AGAINST()语法,混用LIKE会绕过全文索引 - 中文需调
innodb_ft_min_token_size(默认为 2),否则“AI”“DB”这类短词被过滤;生产环境常搭配ngram插件或前置分词
注意:FULLTEXT 不支持通配符模糊,但支持布尔模式(+mysql -oracle)、相关度排序,语义比 LIKE 丰富得多。
别踩坑:这些“优化”实际无效
很多人试过但白忙活的操作:
-
LOCATE('xxx', field) > 0或INSTR(field, 'xxx') > 0→ 和LIKE '%xxx%'一样无法走索引,执行计划仍是type: ALL,还多一层函数计算开销 - 在字段上套函数再查,比如
UPPER(name) LIKE 'ABC%'→ 单纯加索引没用,得建函数索引:CREATE INDEX idx_name_upper ON t1 ((UPPER(name))) - 盲目加前缀索引:
INDEX(name(10))对LIKE '%xxx%'完全无效,只对LIKE 'xxx%'有用
真正容易被忽略的是:字符集/排序规则不一致引发的隐式转换,它不会报错,EXPLAIN 看似走了索引,但 rows 高得离谱——这时候得用 SHOW WARNINGS 看优化器是否悄悄重写了条件。

















