like '%abc' 不走索引,因为b+树仅支持左前缀匹配,后缀模糊导致无法定位起始节点,只能全表扫描;需以explain结果中key为null或type=all为准判断。

为什么LIKE '%abc' 不走索引?B+ 树不支持后缀定位
因为 B+ 树索引只按字段值从左到右排序,name 索引里存的是 '张三'、'李四'、'王五' 这样字典序排列的原始值。查询 WHERE name LIKE '%林' 时,数据库根本不知道该从哪个节点开始查——以“林”结尾的值在树里是完全分散的(比如 '王林' 在叶子页 A,'周林' 在叶子页 F),没法利用有序性跳转。
这和查字典时说“找最后一个字是‘天’的词”一样,字典首页到末页都得翻一遍。MySQL 别无选择,只能退化为全表扫描,执行计划里 type = ALL、key = NULL 就是铁证。
EXPLAIN 是唯一可信的判断依据,别凭感觉猜
即使你写了 WHERE name LIKE '%林',也不能直接断定没走索引——得看 EXPLAIN 输出:
-
key字段为空或为NULL→ 没用索引 -
type是ALL或index→ 全表或全索引扫描,效率低 -
type = range→ 走了索引范围扫描(说明是右模糊,如'林%') -
Extra出现Using filesort或Using temporary→ 即使走了索引,也可能因排序/分组拖慢速度
哪些写法看似模糊,其实还能走索引?
不是所有带通配符的 LIKE 都失效,关键看通配符位置和是否破坏前缀确定性:
-
WHERE name LIKE '张%'→ ✅ 走索引(前缀固定,B+ 树可定位起始点) -
WHERE name LIKE '张_'→ ✅ 走索引(下划线匹配单字符,仍是前缀确定) -
WHERE UPPER(name) LIKE 'ZHANG%'→ ❌ 失效(函数包裹索引列,索引值 ≠ 计算值) -
WHERE name LIKE '%张%'→ ❌ 基本失效(两端模糊,无起点可言;覆盖索引下极少数可能扫索引,但不可依赖)
左模糊真没救了吗?替代方案要权衡代价
如果业务必须做后缀或中间匹配,硬靠 LIKE 只能接受全表扫描,大表会从毫秒变秒级甚至分钟级。可行路径有:
- 改用全文索引(
FULLTEXT) +MATCH ... AGAINST,适合中文需配合 ngram 或第三方分词 - 加冗余字段,比如存
REVERSE(name)并建索引,把LIKE '%林'转成REVERSE(name) LIKE '林%' - 引入 Elasticsearch 或向量数据库,适合高并发、复杂模糊场景
- 前端加约束:禁止纯左模糊输入,引导用户用首字+右模糊(如“林”→“林%”)
真正容易被忽略的点是:联合索引中,哪怕第一个字段满足右模糊,后面字段也大概率失效;而任何对索引列的函数操作(哪怕只是 CONCAT('', name))都会让整个索引失效——这些细节比通配符位置更隐蔽,也更常在线上踩坑。











