mysql如何优化带有like条件的查询_mysql索引失效分析

1次阅读

like查询慢的本质是索引无法跳过全表扫描;当出现前导通配符(如’%abc’或’%abc%’)时,b+树索引失去有序性优势,只能退化为索引扫描或全表扫描,仅’abc%’等左匹配可走范围查询。

mysql如何优化带有like条件的查询_mysql索引失效分析

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 表示全表扫描;rangeref 才算走了索引
  • key 字段:显示实际使用的索引名,为空即未命中
  • rows 字段:预估扫描行数,远大于结果集数量就是低效信号
  • 注意隐式转换:比如 col VARCHAR(50) 被与整数比较(WHERE col = 123),会导致索引失效,LIKE 同理 —— 若字段是 utf8mb4_bin 排序,但查询用的是非二进制 collation,也可能触发隐式转换

真正容易被忽略的是字符集和排序规则不一致引发的隐式转换,它不会报错,但会让 EXPLAIN 显示用了索引,实际性能却接近全表扫描。

text=ZqhQzanResources