右模糊(like 'xxx%')能走索引,因b+树按字典序存储,等价于范围查询name >= 'xxx'且name
右模糊能走索引,左模糊和全模糊必然失效——这不是MySQL的bug,而是B+树索引结构决定的刚性限制。
LIKE 'xxx%' 为什么能走索引?
因为B+树按字段值字典序存储,
name LIKE '华为%'等价于查找所有以“华为”为前缀的连续区间,优化器可以直接定位起始页、顺序遍历,属于典型的范围扫描(type=range)。常见错误:
- 写成name LIKE '%华为'或name LIKE '%华为%'→ 全表扫描
- 在ORM中拼接字符串时漏掉单引号,变成name LIKE %华为%→ SQL语法错误或隐式转换
- 确认字段有单列索引或联合索引的最左前缀位置
- 检查字符集是否统一为
utf8mb4,避免因编码截断导致前缀不匹配- 用
EXPLAIN验证:看到key非空且type是range或ref才算生效必须支持 '%xxx' 或 '%xxx%' 怎么办?
数据库原生B+树索引无法解决这个问题,硬扛只会让500万行表查询从8ms变成12s。别试图“优化SQL”,该换技术栈就得换。
三种真实可用路径:
- 小数据量兜底:表行数 ≤ 5万,且QPS LIKE '%xxx%' + 覆盖索引减少回表,但必须加
LIMIT 100防拖垮- 全文索引替代:MySQL 5.6+ 支持
FULLTEXT,建索引后用MATCH(name) AGAINST('华为' IN NATURAL LANGUAGE MODE),适合商品标题、文章摘要等短文本,但不支持拼音/分词配置- 外置搜索引擎:Elasticsearch 或 Solr 是标准解法,建好
keyword或text类型字段,查q=华为自动命中倒排索引,响应稳定在20ms内注意:
FULLTEXT对中文需额外配置ngram分词器(MySQL 5.7.6+),否则默认按字切分,搜索“华为手机”可能匹配不到“华为”单独出现的记录。为什么不能用函数索引绕过?
MySQL 8.0+ 确实支持函数索引,比如
CREATE INDEX idx_name_rev ON users ((REVERSE(name))),再查REVERSE(name) LIKE REVERSE('华为')+'%'可模拟左模糊——但这只是理论可行。实际踩坑点:
- 函数索引只对精确匹配或右模糊有效,
REVERSE(name) LIKE '%华为'依然失效- 写入时需同步维护反转列,业务逻辑复杂度翻倍
- 多数ORM不识别函数索引,生成SQL时仍会忽略它
- 线上环境MySQL版本多为5.7,8.0函数索引覆盖率不足30%
真正上线的项目里,没人拿函数索引扛模糊搜索,它更适合
UPPER(email)这类确定性转换场景。最常被忽略的一点:模糊查询性能问题,90%出在没做数据分层。原始数据存MySQL,搜索流量打到ES,结果ID再回库捞详情——这个架构不是“过度设计”,而是500万行表能扛住秒杀的前提。












