LIKE以通配符开头时索引完全失效,优化器转为全表扫描;应优先用=或IN,必须模糊匹配时用'abc%'前缀形式,或改用FULLTEXT索引、生成列反转字符串等方案。

LIKE 以通配符开头时索引完全失效
MySQL 的 LIKE 查询中,只要左侧是通配符(如 '%abc' 或 '%abc%'),即使字段上有 B+ 树索引,优化器也会放弃使用索引,转为全表扫描。这是性能骤降的最常见原因。
实操建议:
- 能用
=或IN就不用LIKE—— 比如状态码、类型标识等固定值匹配 - 若必须前缀模糊(如搜索“包含某词”),优先考虑
LIKE 'abc%',它可走索引(最左前缀匹配) - 避免在索引字段上做函数操作,例如
LOWER(name) LIKE '%xxx%'会彻底禁用索引
全文索引(FULLTEXT)更适合中文分词场景
对长文本字段(如文章标题、商品描述)做模糊匹配时,FULLTEXT 索引比 LIKE 更高效,尤其配合 MATCH ... AGAINST 使用。但注意:MyISAM 和 InnoDB 都支持,但 InnoDB 要求 MySQL ≥ 5.6,且中文需依赖内建分词器或第三方插件(如 ngram)。
实操建议:
- 建表时添加
FULLTEXT(title, content),不要等查询慢了再加 - 查询写法必须是
MATCH(title) AGAINST('关键词' IN NATURAL LANGUAGE MODE),不能混用LIKE - ngram 分词长度默认为 2,若搜单字(如“李”),需设
ft_min_word_len=1并重建索引(有风险,慎调)
前导通配符场景下,用生成列 + 函数索引兜底(MySQL 5.7+)
当业务强依赖 LIKE '%xxx'(后缀匹配),又无法改查询逻辑时,可借助生成列(generated column)把反转字符串存下来,再对其建索引。
示例:
ALTER TABLE users ADD COLUMN name_reversed VARCHAR(100) AS (REVERSE(name)) STORED, ADD INDEX idx_name_rev (name_reversed);
然后将原查询 WHERE name LIKE '%john' 改为:
WHERE name_reversed LIKE CONCAT(REVERSE('john'), '%')
这样就能命中 idx_name_rev 索引。注意:STORED 生成列会占用磁盘空间,且写入略慢;VIRTUAL 不落盘但无法建索引。
LIKE 查询被误判为范围扫描导致执行计划失真
有时 EXPLAIN 显示 type=range,看似走了索引,但实际扫描行数极大(rows 值高),这是因为优化器按“最左前缀”估算,而 LIKE 'abc%' 后续字符分布不均(比如大量以 'abc1' 开头),导致索引选择性差。
排查与应对:
- 用
SHOW INDEX FROM table查看Cardinality,越接近总行数说明区分度越高 - 对低区分度字段(如性别、状态),别单独建索引,考虑联合索引中放后面
- 必要时加
FORCE INDEX强制走某个索引,但要配合EXPLAIN验证效果
LIKE 中混用函数、隐式类型转换、或跨多字段拼接条件时,执行计划很容易偏离预期。











