MySQL-like是否可以使用索引
如果你读了这篇文章 Innodb和MyISAM索引的区别 ,你了解索引的结构后,就很容易明白了。
简单直接的回答:可以使用索引,但有一个非常著名的“最左前缀”限制。俗称:左模糊('%a')走不了索引,右模糊('a%')可以走索引。
如果是中间 '%a%',触发覆盖索引,即列刚好就是索引列本身,就能走索引,否则不行。
# 一、 核心匹配原理:为什么“左模糊”不行,“右模糊”可以?
MySQL 的默认索引是 B+ 树索引,它是严格按照从左到右的顺序对字符进行排序的。
假设我们对 name 字段建了索引,索引树里排好序的数据长这样:
apple` ——> `banana` ——> `cat` ——> `dog`
# 1. 右模糊:LIKE 'a%'(走索引:Range Scan)
- SQL 示例:
SELECT * FROM users WHERE name LIKE 'a%'; - 底层匹配过程:MySQL 拿着英文字母
a去 B+ 树里找。因为树是排好序的,它能瞬间定位到以a开头的第一个单词(apple),然后顺着链表往后读,直到遇到不是a开头的单词为止。 - 结果:成功触发索引范围扫描,效率很高。
# 2. 左模糊:LIKE '%a'(不走索引:Full Table Scan)
- SQL 示例:
SELECT * FROM users WHERE name LIKE '%a'; - 底层匹配过程:你想找以
a结尾的单词。但在 B+ 树里,数据是按开头字母排序的(apple、banana在不同分支)。对于以什么结尾,整棵树是完全无序的。 - 结果:MySQL 无法在树分支里做二分查找,只能被迫放弃索引,进行全表扫描(Full Table Scan)。
# 3. 双模糊:LIKE '%a%'(不走索引)
- 道理同上,开头字母不确定,B+ 树直接瘫痪,只能全表扫描。
# 二、 实战特例:两招让“左/双模糊”也能走索引
在实际生产中,如果业务逼得你非要用 LIKE '%a' 或 LIKE '%a%',有以下两个经典的调优方案:
# 1. 覆盖索引(Index Coverage)—— 绕过全表扫描
如果你的查询语句里,SELECT 的列刚好就是索引列本身,哪怕你写 LIKE '%a%',它也会走索引。
例子:
-- 假设 name 字段有索引 SELECT name FROM users WHERE name LIKE '%a%';为什么能走索引? 因为索引树本身就包含了
name字段的完整数据,而且索引树的体积远比存放整行数据的“聚簇索引(表本身)”小得多。MySQL 优化器一看:“反正都要全扫描,那我直接去扫描体积更小的name索引树好了。” 在EXPLAIN里你会看到 type 是index(索引全扫描),虽然比不上range,但比全表扫描(ALL)快得多。
# 2. 虚拟列 + 倒序索引(Reverse Index)—— 解决左模糊的奇招
如果你要频繁查手机号后四位(LIKE '%1234')或者 域名呢?。
- 绝招:在数据库里多存一个字段
name_reversed,把字符串倒过来存(比如apple存成elppa)。然后对这个倒序字段建索引。 - 改写查询:把
LIKE '%1234'改写为针对倒序字段的右模糊查询:LIKE '4321%'。 - 结果:成功完美压榨 B+ 树索引!
# 三、总结
| LIKE 表达式 | 能否走索引 | 索引类型 (type) | 底层原理 |
|---|---|---|---|
LIKE 'abc%' | 能 | range | 匹配前缀,利用 B+ 树有序性直接定位 |
LIKE '%abc' | 不能 | ALL (除非触发覆盖索引) | 尾部无序,被迫全表扫描 |
LIKE '%abc%' | 不能 | ALL (除非触发覆盖索引) | 中间无序,被迫全表扫描 |
LIKE 'ab_c%' | 能 | range | 前两个字符固定,依然能利用前缀定位 |
上次更新: 2026-06-25 17:18:05