索引问题
在 MySQL 的 B+ 树索引中,最左前缀匹配原则的核心逻辑是:索引是按照最左列的顺序逐层排序的,查询条件必须从索引的最左边开始连续匹配,才能有效利用索引。
对于 LIKE 前缀查询,能不能走最左前缀匹配,关键看 通配符 % 或 _ 的位置:
✅ 可以走最左前缀匹配的情况
1. LIKE 'prefix%' — 通配符在末尾
-- 假设索引为 idx(name)
SELECT * FROM users WHERE name LIKE 'abc%';
原理:'abc%' 表示查找以 abc 开头的字符串。在 B+ 树索引中,所有以 abc 开头的记录会连续存放在索引的某个区间里。MySQL 可以定位到第一个满足 >= 'abc' 的位置,然后顺序扫描直到不满足 < 'abd'(或前缀边界)为止。
效果:走 range 扫描,利用索引快速定位。
❌ 走不了最左前缀匹配的情况
1. LIKE '%suffix' — 通配符在开头
SELECT * FROM users WHERE name LIKE '%abc';
原理:以 abc 结尾的字符串在 B+ 树中不是连续存储的(xyzabc、123abc 等分散在不同分支)。索引无法从根节点逐层定位。
效果:全表扫描(或全索引扫描),无法利用最左前缀。
2. LIKE '%infix%' — 通配符在两边
SELECT * FROM users WHERE name LIKE '%abc%';
原理:中间包含 abc 的记录分布更散,索引完全无法提供有序性支持。
效果:全表扫描。
⚠️ 特殊场景与例外
1. 覆盖索引(Covering Index)
即使 LIKE '%abc%' 无法走最左前缀,如果查询的所有列都在索引中:
-- 假设索引为 idx(name, age),查询只涉及这两列
SELECT name, age FROM users WHERE name LIKE '%abc%';
MySQL 可能会选择 全索引扫描(Using index),虽然仍需扫描整个索引,但避免了回表,比全表扫描快。
2. 索引条件下推(ICP, Index Condition Pushdown)
MySQL 5.6+ 中,即使 LIKE '%abc%' 无法利用索引定位,如果存储引擎能在索引遍历过程中直接过滤条件,可以减少回表次数:
-- 有索引 idx(name, status)
SELECT * FROM users WHERE name LIKE '%abc%' AND status = 1;
ICP 可以在索引层面先过滤 status,再对 name 做 LIKE 判断,但这仍然不是最左前缀匹配,只是减少了 I/O。
3. 前缀索引(Prefix Index)
如果你创建的是前缀索引(如 INDEX (name(10))),则最左前缀匹配只适用于这前 10 个字符:
-- 可以走前缀索引
WHERE name LIKE 'abcdefghij%'
-- 如果前缀部分全是通配符,仍然不行
WHERE name LIKE '%defghij'
总结速查表
| 写法 | 能否走最左前缀 | 扫描方式 |
|---|---|---|
LIKE 'abc%' |
✅ 可以 | 索引 range 扫描 |
LIKE 'abc_def%' |
✅ 可以(_ 匹配单字符) |
索引 range 扫描 |
LIKE '%abc' |
❌ 不可以 | 全表/全索引扫描 |
LIKE '%abc%' |
❌ 不可以 | 全表/全索引扫描 |
LIKE 'a%bc' |
⚠️ 部分可以 | 先走 a% 的 range,再过滤 bc |
核心记忆点:B+ 树索引是"从左到右"排序的,只有尾部通配符能保留左侧的有序性,从而触发最左前缀匹配。

浙公网安备 33010602011771号