mysql中like '%abc'或'%abc%'一定全表扫描,因b+树索引仅支持最左前缀匹配,%开头无法定位起始节点,只能逐行检查;而'abc%'可定位起点并范围扫描。

MySQL 中 LIKE 查询本身不会“导致”索引失效,真正失效的是 B+ 树索引对模糊模式的匹配能力——关键在通配符位置和索引结构的不兼容。
LIKE '%abc' 或 LIKE '%abc%' 为什么一定走全表扫描
B+ 树索引按字段值字典序存储,只能从某个确定前缀开始向右遍历。当模式以 % 开头时,MySQL 无法定位起始节点,必须检查每一行。
-
LIKE 'abc%'→ 找到第一个 ≥'abc'的记录,向右扫完所有前缀匹配项(type=range) -
LIKE '%abc'→ 要找结尾为'abc'的字符串,B+ 树不存反向顺序,无起点可言(type=ALL) -
LIKE '%abc%'→ 两端都模糊,同样无法锚定起点(MySQL 8.0+ 仍不支持,key=NULL)
复合索引下 LIKE 'abc%' 能用索引,但有隐藏限制
即使写成 LIKE 'abc%',若它出现在联合索引中间或右侧,也可能只用到部分列。
- 索引为
(a, b, c),WHERE a = 'x' AND b LIKE 'y%' AND c = 'z'→ 可用全部三列 - 索引为
(a, b, c),WHERE a = 'x' AND c LIKE 'z%'→ 实际只用到a,c被跳过(违反最左前缀) - 索引为
(name, email),WHERE name LIKE 'john%' AND email = 'a@b.c'→ 可用,且若只查这两列,还能触发覆盖索引优化
不改 SQL 逻辑的前提下,有哪些可行修复路径
没有银弹,方案取决于数据长度、查询频率和更新压力。
- 短字段(如用户名、编码):优先用
LIKE 'prefix%'+ 单列索引,避免%开头 - 中长文本(如标题、简介):建
FULLTEXT索引,改用MATCH(name) AGAINST('keyword')(注意自然语言模式 vs 布尔模式) - 必须支持任意位置匹配且字段较短:考虑生成反向索引列(如
name_reversed),查询时WHERE name_reversed LIKE REVERSE('abc') + '%',再加普通索引 - 高频模糊查但能接受轻微延迟:引入 Elasticsearch 或 SQLite FTS,MySQL 仅作主库
最容易被忽略的一点是:即使加了 FULLTEXT 索引,AGAINST 中的搜索词若少于 ft_min_word_len(默认 4),依然查不到——别只盯着 LIKE,忘了查 MySQL 全文配置。











