LIKE '%abc' 变慢是因为B+树索引不支持前导通配符,导致全表扫描;仅LIKE 'abc%'等前缀匹配可走索引,中间或开头含%均失效,且受collation、函数包裹等因素影响索引使用。

LIKE 为什么在开头加 % 就变慢
因为数据库无法用索引做前缀匹配,LIKE '%abc' 必须全表扫描——B+ 树索引只支持从左到右的最左前缀匹配,% 在开头等于放弃索引定位能力。
常见错误现象:EXPLAIN 显示 type: ALL、key: NULL,哪怕字段上有索引也完全不走。
使用场景:模糊搜索用户昵称、商品标题、日志内容等“包含某字符串”的需求,但业务上往往误以为 LIKE '%关键词%' 是唯一写法。
- MySQL 5.7+、PostgreSQL、SQL Server 都受此限制,行为一致
- Oracle 的
LIKE同样不走索引(除非配合函数索引或全文索引) - 即使加了
FORCE INDEX也没用,优化器知道索引无效,强制也没意义
能用索引的 LIKE 写法有哪些
只有 LIKE 'abc%' 这类前缀固定、后缀可变的模式才能走索引;LIKE 'ab%c' 中间有 % 也不行。
实操建议:
- 把搜索逻辑前置:比如用户输入“张”,就查
name LIKE '张%',而不是等用户输完再查name LIKE '%张%' - 对短字段(如城市名、状态码)可建前缀索引:
INDEX (city(10)),配合LIKE '上海%'有效 - 避免
LOWER(name) LIKE LOWER('%abc%')—— 函数调用直接让索引失效,改用大小写不敏感的 collation(如utf8mb4_unicode_ci)
替代 LIKE '%xxx%' 的实用方案
真要支持任意位置匹配,硬扛 LIKE '%xxx%' 是下策。更可行的是换技术路径。
常见选择对比:
- MySQL 全文索引(
FULLTEXT):适合中文需搭配ngram插件,且仅支持MATCH ... AGAINST,不能混用AND条件太多时性能下降明显 - PostgreSQL 的
pg_trgm+GIN索引:对ILIKE '%xxx%'有加速效果,但索引体积大、写入略慢 - 独立搜索引擎(Elasticsearch / Meilisearch):适合复杂检索、高并发、需要相关性排序的场景,但引入运维复杂度
- 生成反向索引表:比如对 title 字段拆出所有长度为 2–4 的子串,存进关联表,查
'abc'就去查substring = 'abc'—— 适合更新不频繁、查询极多的场景
容易被忽略的 COLLATION 和字符集影响
同一个 LIKE 'abc%',在 utf8mb4_bin 和 utf8mb4_unicode_ci 下表现可能不同:前者严格区分大小写和重音,后者可能让索引范围扫描变宽甚至失效。
实操要点:
- 检查字段 collation:
SHOW FULL COLUMNS FROM table_name LIKE 'column_name'; - 避免在
WHERE中混用不同 collation 的列比较,会触发隐式转换,导致索引失效 - MySQL 8.0+ 的
utf8mb4_0900_as_cs对大小写敏感且支持索引优化,比旧的_bin更可靠 - 中文场景下,
utf8mb4_unicode_ci可能导致“张”和“張”被当成相同字符,影响准确性,别盲目设成 insensitive
LIKE,而取决于通配符位置、collation、是否被函数包裹、以及字段实际数据分布。很多 case 表面是 SQL 写法问题,根子在早期 schema 设计没预估好模糊查询强度。

















