like查询索引失效是b+树索引固有限制所致,仅支持左前缀匹配;要走索引需满足条件:name like 'abc%' 或 name >= 'abc' and name
LIKE查询索引失效不是配置问题,而是B+树索引的固有限制——它只支持左前缀匹配。想让它走索引,必须让查询条件能转化为“>= 起始值 AND
LIKE 'abc%' 为什么能走索引?
因为优化器会把它重写为
name >= 'abc' AND name ,B+树能直接定位起始页并顺序遍历。但前提是:
name字段上必须有单列索引,或位于联合索引的最左位置(如(name, status))- 不能对字段用函数:
UPPER(name) LIKE 'ABC%'→ 索引必然失效- 字符集要一致:如果
name是utf8mb4_0900_as_cs,而查询字面量是'abc'(默认 collation),MySQL 可能隐式转换,导致key在EXPLAIN中显示为NULL- 区分度太低时优化器会主动放弃:比如
LIKE 'a%'匹配超过 25% 行,type可能变成ALL—— 先用SELECT COUNT(*) FROM t WHERE name LIKE 'a%'估算比例LIKE '%abc' 或 '%abc%' 怎么办?
这类查询 MySQL 原生无法走 B+ 树索引,硬加索引没用。别在
WHERE里死磕LIKE,换思路:
- 用全文索引:
ALTER TABLE t ADD FULLTEXT(name),再查MATCH(name) AGAINST('abc' IN NATURAL LANGUAGE MODE)—— 适合长文本、支持分词和相关性排序,但中文需额外分词插件或升级到 MySQL 8.0.30+ 内置 ngram- 后缀匹配可反转存储:
ALTER TABLE t ADD COLUMN name_rev VARCHAR(255) AS (REVERSE(name)) STORED,再建索引INDEX idx_name_rev (name_rev),查时写成name_rev LIKE 'cba%'- 业务层妥协:把“搜索标题含关键词”改成“标题以关键词开头”,或加筛选条件(如
status = 'active')缩小数据集后再LIKE,避免全表扫描覆盖索引能缓解但不能根治
即使
LIKE 'abc%'走了索引,SELECT *还是要回表取完整行。用覆盖索引能把 I/O 降下来:
- 把常用查询字段全塞进索引里:
CREATE INDEX idx_name_cover ON t (name, id, created_at, email)- 注意顺序:
name必须放最左,后面字段按SELECT和ORDER BY需求排- 别贪多:加太多字段会让索引变大,写入变慢,还可能挤占 buffer pool —— 查
information_schema.INNODB_INDEX_STATS看实际大小真正卡住性能的,往往不是没建索引,而是没意识到
LIKE的能力边界。一旦需求要求任意位置匹配,就得接受:MySQL 不是搜索引擎,该交出去的查询,就别硬留在 SQL 层里扛。












