LIKE 查询为什么慢?本质是索引无法跳过全表扫描
当
WHERE name LIKE '%abc'或
WHERE name LIKE '%abc%'出现时,MySQL 通常无法使用 B+ 树索引的有序性做快速定位,只能从索引最左前缀开始逐条比对,最终退化为索引扫描(index scan)甚至全表扫描(table scan)。只有
LIKE 'abc%'这种左匹配才可能走索引范围查询。
哪些 LIKE 写法能用上索引?看前导通配符是否存在
能否命中索引,关键看通配符是否出现在模式最左侧:
WHERE col LIKE 'abc%'→ 可用索引,B+ 树按字典序查找以
'abc'开头的所有值
WHERE col LIKE 'ab_c'→ 可用索引(下划线只占一位),仍属于左匹配前缀
WHERE col LIKE '%abc'→ 索引失效,必须倒序扫描,MySQL 不支持反向索引遍历
WHERE col LIKE '%abc%'→ 索引失效,无有效起始点
WHERE col LIKE 'ab%c'→ 索引部分生效,只加速到
'ab'前缀,后续仍需字符串匹配
除了改写 LIKE,还有哪些实际可行的优化手段?
不能改 SQL?那就绕开 LIKE。常见且有效的替代路径有:
用全文索引 +MATCH ... AGAINST()替代模糊匹配,尤其适合中文需配合
ngram插件或
MeCab对固定长度后缀查询(如查文件扩展名),可新增计算列:
ALTER TABLE t ADD COLUMN ext VARCHAR(10) STORED AS (SUBSTRING_INDEX(filename, '.', -1)),再对
ext建索引 将高频模糊搜索字段同步到 Elasticsearch 或 RedisSearch,由专用搜索引擎承担 如果业务允许,把
LIKE '%keyword%'拆成“关键词前置”+“关键词后置”两个条件并集,再用覆盖索引减少回表
如何确认你的 LIKE 查询到底有没有走索引?
别猜,用
EXPLAIN看执行计划,重点关注这几项:
type字段:出现
ALL表示全表扫描;
range或
ref才算走了索引
key字段:显示实际使用的索引名,为空即未命中
rows字段:预估扫描行数,远大于结果集数量就是低效信号 注意隐式转换:比如
col VARCHAR(50)被与整数比较(
WHERE col = 123),会导致索引失效,LIKE 同理 —— 若字段是 utf8mb4_bin 排序,但查询用的是非二进制 collation,也可能触发隐式转换
真正容易被忽略的是字符集和排序规则不一致引发的隐式转换,它不会报错,但会让
EXPLAIN显示用了索引,实际性能却接近全表扫描。
