like查询能否走索引取决于通配符位置:仅右模糊('abc%')可用索引,左模糊('%abc')和全模糊('%abc%')失效;全模糊可通过覆盖索引缓解但不根治;高频任意位置模糊应换elasticsearch等专用方案。

LIKE 通配符位置决定索引是否生效
MySQL 的 LIKE 查询能否走索引,核心就看 % 出现在哪儿:只有右模糊('abc%')能用索引;左模糊('%abc')或全模糊('%abc%')直接失效,退化为全表扫描。
-
WHERE name LIKE '张%'→ 走索引(B+树前缀匹配有效) -
WHERE name LIKE '%三'→ 不走索引(无法定位起始位置) -
WHERE name LIKE '%张三%'→ 不走索引(两端都不确定)
这不是 MySQL 傻,而是 B+ 树索引本质只支持「从左到右」的有序查找。一旦开头不可知,就只能扫全表。
覆盖索引是全模糊查询的唯一补救手段
当业务真要查 '%张三%',又不能换 Elasticsearch,唯一能抢救性能的方式是:让查询变成「覆盖索引」——即 SELECT 的字段全部来自联合索引,且满足最左前缀。
- 建索引:
ALTER TABLE user ADD INDEX idx_name_email (name, email); - 写 SQL:
SELECT name, email FROM user WHERE name LIKE '%张三%';(注意:不能SELECT *,也不能加age这类没进索引的字段) - 原理:不回表 → 避免磁盘随机 IO;即使扫描索引页,也比扫聚簇索引快得多
但注意:覆盖索引只缓解 IO 压力,扫描量仍大。数据量超 10 万行后,响应延迟依然明显。
替代方案比硬扛模糊更靠谱
真要高频支持任意位置模糊,靠 B+ 树索引就是缘木求鱼。该换技术栈时别硬刚:
- 中文分词搜索 → 上
MySQL FULLTEXT(仅 MyISAM/InnoDB 5.6+,且对中文支持弱,需配合 ngram) - 高精度全文检索 → 接入
Elasticsearch或Meilisearch,它们专为prefix/infix设计 - 简单替代写法 → 用
LOCATE('张三', name) > 0或INSTR(name, '张三'),虽然也不走索引,但语义清晰、可读性强,且某些场景下优化器能更好预估成本
别迷信“必须用 LIKE”,先问一句:这个模糊查询是不是本就不该在 OLTP 数据库里实时跑?
字符串不加引号和类型隐式转换会悄悄废掉索引
一个常被忽略的坑:WHERE name LIKE 张三%(漏了单引号)→ MySQL 当成变量或列名处理,报错或转为全表扫描;更隐蔽的是字段类型与传参不一致,比如 name 是 VARCHAR,但传入数字 123,触发隐式转换,索引立即失效。
- 错误示例:
WHERE name LIKE 123%(数字开头,无引号) - 危险示例:
WHERE phone LIKE '138%' AND id = '100'(id是 INT,却用字符串比较) - 检查方法:用
EXPLAIN看key是否为NULL,type是否跌到ALL或index
所有字符串值,无论参数化还是拼接,务必加单引号;所有比较操作,确保字段类型与字面量/参数类型严格一致。










