P30 前模糊索引失效
面试题:LIKE '%关键字'(前模糊)为什么索引失效?怎么优化?
1. 为什么前模糊索引失效
B+ 树索引是按从左到右有序组织的。LIKE 'abc%' 能用索引,因为可以定位到以 abc 开头的区间;
而 LIKE '%abc'、LIKE '%abc%' 的前置部分不确定,无法利用索引的顺序性直接定位起点,只能全索引扫描/全表扫描,所以索引失效。
sql
SELECT * FROM t WHERE name LIKE '%张'; -- 前模糊,索引失效
SELECT * FROM t WHERE name LIKE '张%'; -- 后模糊,可走索引2. 为什么"xxx%"可以走索引
索引键有序排列,LIKE '张%' 相当于范围查询 name >= '张' AND name < '王'(或 > '张' 且 < '张'+1 的范围),B+ 树可以二分定位起点后顺序扫描。
3. 优化方案
① 修改查询方式(业务允许时)
- 把前模糊改成后模糊/等值:
name LIKE '张%'; - 搜索场景尽量用全文检索(Elasticsearch / MySQL FULLTEXT / ngram 分词),而不是 LIKE 前模糊。
② 反转存储
对需要前模糊的字段,存一份反转后的值(如 name_rev = 反序字符串),查 %张 变成查 张%:
text
原值: "张三" → name_rev: "三张"
查询: LIKE '%张' → 变成 name_rev LIKE '张%' → 走索引③ 覆盖索引 + 强制扫描优化
前模糊无法避免时,让扫描尽量轻:查询列都在索引里(覆盖索引),减少回表;配合 LIMIT 控制扫描量。
④ 拆表/冗余字段
高频搜索字段单独建表或冗余可检索的正排结构,用 ES 等专门组件。
加分点
- 追问"
LIKE 'abc%def'能走索引吗":能部分利用——abc%走索引区间,%def部分在回表/引擎层过滤; - 面试官还可能问"为什么索引能加速排序/范围":因为 B+ 树叶子节点有序链表;
- 字符集 collation 影响模糊匹配行为,一般不影响"前模糊失效"的结论。
一句话总结
前模糊 LIKE '%x' 无法利用 B+ 树的有序定位,只能全扫描所以索引失效;优化用"改后模糊/等值、反转字段、全文检索、覆盖索引",核心是让查询能落到索引的有序区间上。