like '%xxx'一定不走b+树索引,因b+树按字典序从左到右排序,无法定位结尾匹配的起点,只能全表扫描;仅like 'xxx%'等前缀确定模式可走索引。

因为 LIKE 模式以 % 开头时,B+ 树索引根本无法定位扫描起点——这不是 MySQL 故意不用索引,而是索引结构本身不支持。
为什么 LIKE '%xxx' 一定不走 B+ 树索引
B+ 树索引按字段值字典序从左到右严格排序,查找必须能“定起点”。LIKE 'xxx%' 可跳到第一个 'xxx' 开头的记录,再向右范围扫描;而 LIKE '%xxx' 要求结尾是 'xxx',匹配值可能散落在 'a-xxx'、'zzz-xxx'、'xxx' 等任意位置,起点不可知,优化器只能放弃索引,选全表扫描。
常见错误现象:EXPLAIN 显示 type: ALL、key: NULL,哪怕字段有单列索引或在联合索引最左位,也完全不生效。数据量过 10 万后,查询从毫秒级拖到数秒甚至超时。
LIKE 哪些写法才能真正触发索引
只有一种本质条件:左侧前缀确定、无通配符干扰。是否走索引,和字段类型、索引长度、统计信息都无关,只看模式字符串本身。
-
LIKE '张%'→ ✅ 走索引(type: range),支持前缀匹配 -
LIKE '张_明'→ ✅ 走索引(_占一位,不影响前缀定位) -
LIKE '%张%'→ ❌ 全表扫描,前后都模糊,索引彻底失效 -
LIKE '张%明'→ ⚠️ 仅'张%'部分生效,'%明'不参与索引过滤
注意:LIKE 后必须是字面量或参数化变量(如 ? 或 @p),不能是表达式,比如 CONCAT('%', @kw)——这会导致隐式计算,索引照样失效。
中文场景下字符集和排序规则的“暗坑”
即使写成 LIKE '张%',中文仍可能查不到或不走索引,根源常在字符集不一致:
- 表/列用
utf8mb4,但客户端连接用latin1→ 查询时发生隐式转换,索引列被CAST,索引失效 - 排序规则用
utf8mb4_general_ci,遇到“張”和“张”这种简繁差异,可能无法命中同一索引分支 - 建表未显式指定
COLLATE,依赖服务器默认值 → 不同环境行为不一致
验证方法:运行 SHOW CREATE TABLE users; 确认列定义含 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;再查连接变量:SHOW VARIABLES LIKE 'character_set%'; 和 SHOW VARIABLES LIKE 'collation%';,确保 client/connection/results 三者一致。
真要支持后缀匹配,别硬改 SQL
LIKE '%xxx' 是 B+ 树的硬限制,不是 bug,也不是配置问题。换索引类型或换查询方式才是正解:
- 用
FULLTEXT索引(需MATCH AGAINST语法,且仅支持英文分词或中文ngram插件) - 把后缀匹配转为前缀匹配:对字段存
REVERSE(name),查时写WHERE reversed_name LIKE REVERSE('xxx') + '%' - MySQL 8.0+ 可直接建函数索引:
ALTER TABLE users ADD INDEX idx_name_reverse ((REVERSE(name)));
最容易被忽略的是:你以为走了索引,其实只是“扫了索引”。EXPLAIN 里 type = index 是全索引扫描,性能和全表扫描差别不大,尤其当索引字段较宽、回表代价高时,反而更慢。真正有效的信号是 key 显示用了哪个索引,且 rows 明显小于总行数。











