索引问题

在 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+ 树中不是连续存储的(xyzabc123abc 等分散在不同分支)。索引无法从根节点逐层定位。

效果全表扫描(或全索引扫描),无法利用最左前缀。

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,再对 nameLIKE 判断,但这仍然不是最左前缀匹配,只是减少了 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+ 树索引是"从左到右"排序的,只有尾部通配符能保留左侧的有序性,从而触发最左前缀匹配。

posted @ 2026-07-28 10:27  ruo_feng  阅读(9)  评论(0)    收藏  举报
-->