like '%xxx' 一定不走b+树索引,因其无法确定扫描起点;仅like 'xxx%'等前缀确定的模式才能走索引,后缀匹配需改用fulltext、reverse字段或外部搜索引擎。

LIKE '%xxx' 为什么一定走不了 B+ 树索引
不是 MySQL 故意不走,是 B+ 树结构根本做不到。索引节点按字典序从左到右排列,查找必须能“定起点”。LIKE 'xxx%' 可以跳到 'xxx' 开头的第一条记录,然后向右范围扫描;而 LIKE '%xxx' 要求结尾是 'xxx',可能出现在 'a-xxx'、'zzz-xxx'、'xxx' 任意位置——起点完全不可知,优化器只能放弃索引,选全表扫描。
常见错误现象:
-
EXPLAIN显示type: ALL、key: NULL - 哪怕
name字段有单列索引或在联合索引最左位,也完全不生效 - 数据量过 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,换技术栈
试图靠加 HINT、调统计信息、建复合索引、改 REGEXP 都没用。LIKE '%xxx' 是 B+ 树的硬限制,不是 bug,也不是配置问题。
- 换索引类型:用
FULLTEXT索引(需MATCH ... AGAINST语法,且仅支持英文分词或中文 ngram 插件) - 换查询方式:把后缀匹配转为前缀匹配,例如对字段存
REVERSE(name),查时写WHERE reversed_name LIKE 'xxx%' - 换引擎:数据量大、模糊需求多,直接上 Elasticsearch 或 MeiliSearch
最容易被忽略的一点:哪怕用了覆盖索引(比如只查 id 和 name,而这两列都在二级索引里),type 变成 index 也不等于“走索引优化了”——它只是遍历了更小的辅助索引树,仍是全量扫描,性能提升有限,不能当真解。











