LIKE '%keyword%' 永远无法使用 B+ 树索引,因其无确定起点,必然全表扫描;仅 LIKE 'abc%' 或 LIKE 'ab_c' 等前缀确定写法可走索引。

“%关键词%”永远用不上 B+ 树索引,这不是写法或配置问题,是 MySQL 索引结构决定的硬限制。别折腾 hint、复合索引或覆盖索引,它们对左模糊无效。
为什么 LIKE '%keyword%' 一定全表扫描
B+ 树索引按字典序存储,查找必须能定位一个起点再向右遍历。LIKE 'keyword%' 可以从 “keyword” 开始扫;而 LIKE '%keyword%' 没有确定起点,MySQL 只能逐行取值、截取后缀/全文比对——执行计划里 type 必为 ALL,key 必为 NULL。
常见误判点:
- 加
INDEX(status, name)想救name LIKE '%xxx'——name字段在该索引中完全不可用 - 改写成
name REGEXP 'keyword$'或name REGEXP 'keyword'—— 正则同样不支持索引加速 - 看到
EXPLAIN显示用了某个索引,就以为LIKE走了索引 —— 实际可能是status = 1等其他条件带来的假象
哪些 LIKE 写法真能走索引
只有满足「前缀可确定性」的写法才有效,优化器必须能算出扫描边界:
-
LIKE 'abc%'✅:B+ 树从字典序 “abc” 起点向右遍历 -
LIKE 'ab_c'✅:_是单字符通配,不破坏前缀连续性 -
LIKE 'ab%c'❌:中间有%,无法确定右边界 -
LIKE '%abc%'❌:两端都模糊,无起点也无终点
如果字段平均长度很短(比如姓名平均 6 字符),但定义为 VARCHAR(255),可建前缀索引:INDEX(name(8)),减小索引体积、提升写入性能。
真正可用的替代方案不是“调优”,而是换技术栈
业务上真需要任意位置匹配(如搜索商品标题含“充电宝”),硬扛 LIKE '%keyword%' 在万级以上数据量就会卡死。这时候得跳出 SQL 层选型:
- 小表临时兜底:数据量 ≤ 1 万行,且 QPS 极低,可接受秒级响应,才考虑保留
-
全文索引:适合字段内容较长(如文章、描述)、搜索词不固定、需相关性排序。要求 MySQL ≥ 5.6 + InnoDB,且只能建在
CHAR/VARCHAR/TEXT列上,语法必须用MATCH(col) AGAINST(...),不能混LIKE -
外部搜索引擎:高并发、带高亮/分词/拼写纠错等需求,标准做法是引入
Elasticsearch或Meilisearch,MySQL 只存原始数据
冗余字段预处理也是可行路径:比如把标题关键词提取为 tags JSON 字段,或拆成逗号分隔的 keyword_list,配合 FIND_IN_SET() 或 JSON_CONTAINS() 查询——前提是关键词可枚举、更新不频繁。
中文场景额外注意字符集和排序规则
中文模糊失效常不是索引问题,而是字符处理异常:
- 表/列用
utf8(即utf8mb3)但存了 4 字节 emoji 或生僻汉字,会导致截断或比较失败,看起来像“没结果” - 连接字符集(
character_set_connection)与列字符集(utf8mb4)不一致,触发隐式转换,索引直接失效 - 排序规则用
utf8mb4_general_ci时,部分中文比较不准确;建议统一用utf8mb4_unicode_ci
验证方法:SHOW VARIABLES LIKE 'character_set%'; + SHOW CREATE TABLE your_table;,确保三者一致。



















