like '%xxx'一定不走索引,因b+树依赖前缀可确定性,无法定位扫描起点,只能全表扫描;复合索引、正则、函数包裹均无效,唯一解是全文索引或外部搜索引擎。

LIKE '%xxx' 为什么一定走不了索引
因为 B+ 树索引的查找依赖「前缀可确定性」——它只能从某个确定的字典序起点向右遍历。LIKE 'xxx%' 能定位到第一个 'xxx' 开头的值,然后顺序扫;而 LIKE '%xxx' 没有起点,MySQL 必须检查每一行末尾是否含 'xxx',执行计划里 type 一定是 ALL,key 是 NULL。
常见误判点:
- 加复合索引如
(status, name)也救不了name LIKE '%xxx'—— 只要name上是左模糊,该字段在索引中就完全不可用 -
WHERE name REGEXP 'xxx$'同样不走索引,正则和LIKE一样,都不支持后缀索引 - 字符集不一致会触发隐式转换,比如
COLLATION(name)是utf8mb4_0900_as_cs,但查询字面量没声明 collation,MySQL 就可能放弃索引
哪些 LIKE 形式能真正用上索引
只有严格满足「左前缀匹配」的写法才有效。不是“看起来像前缀”就行,得让优化器能算出扫描边界。
-
LIKE 'abc%'✅ 可用:B+ 树从'abc'起始位置向右遍历 -
LIKE 'ab_c'✅ 可用:_是单字符通配,不破坏前缀连续性 -
LIKE 'ab%c'❌ 不可用:中间有%,无法确定右边界 -
LIKE '%abc%'❌ 不可用:两端都模糊,无起点也无终点
如果字段实际值很短(比如平均长度 8),但定义为 VARCHAR(255),可以建前缀索引:INDEX (name(10)),减小索引体积、提升写入性能。
全文索引替代 LIKE 的实操要点
适合字段内容较长(如商品描述、文章标题)、搜索词不固定、需相关性排序的场景。不是所有模糊需求都适用,但对「包含某词」类查询最直接。
- 确认 MySQL 版本 ≥ 5.6,且存储引擎是 InnoDB(InnoDB 全文索引从 5.6 开始支持)
- 全文索引只支持
CHAR、VARCHAR、TEXT,不能建在INT或函数表达式上 - 必须用
MATCH(col) AGAINST(...)语法,混用LIKE会绕过全文索引 - 停用词(如“的”、“和”)和短词(默认
ft_min_word_len=4)不会被索引,需调整配置并重建索引
示例:ALTER TABLE users ADD FULLTEXT(name);,之后查 MATCH(name) AGAINST('john' IN NATURAL LANGUAGE MODE)。
业务必须支持任意位置匹配时的替代方案
硬扛 LIKE '%keyword%' 在数据量稍大时就会卡死。这时候得跳出 SQL 层做架构选择:
- 引入 Elasticsearch 或 Meilisearch:适合高并发、复杂检索、高亮、分词、拼写纠错等场景,MySQL 只存原始数据
- 冗余字段预处理:比如把标题关键词提取成
tags JSON字段,或用逗号分隔的字符串存进tags,再用FIND_IN_SET()+ 普通索引匹配 - 避免踩坑:
WHERE UPPER(name) LIKE '%ABC%'这类写法必然失效,函数包裹字段会让索引完全不可用
真正卡住性能的,往往不是没建对索引,而是没意识到「B+ 树只认左前缀」这个硬约束。一旦需求突破它,就得在全文索引、外部搜索引擎、冗余设计之间做取舍,而不是反复改 WHERE 条件或加 hint。











