mysql中如何优化LIKE语句的索引使用

来源:这里教程网 时间:2026-02-28 20:41:09 作者:

LIKE 以通配符开头时索引完全失效

WHERE name LIKE '%abc'
WHERE name LIKE '%abc%'
这类查询出现时,MySQL 无法使用 B+ 树索引的有序性,会直接走全表扫描。这是因为索引是按字典序存储的,而前导通配符让数据库无法确定从哪个叶子节点开始查找。

唯一能走索引的
LIKE
形式是
WHERE col LIKE 'abc%'
(前缀匹配),此时可利用索引快速定位到
'abc'
开头的所有记录
WHERE col LIKE 'ab_c'
(单字符通配)也能用索引,因为长度固定、前缀明确
注意:即使字段有索引,只要左侧带
%
EXPLAIN
中的
type
字段就会显示为
ALL

用覆盖索引 + 前缀索引缓解性能问题

如果业务必须支持模糊搜索但又不能全表扫,可以结合字段特性做针对性优化。例如用户昵称搜索,通常只关心前 20 个字符:

ALTER TABLE users ADD INDEX idx_nickname_prefix (nickname(20));

这样

WHERE nickname LIKE '张%'
就能命中该前缀索引,节省空间且提升查询效率。但要注意:

前缀长度不能太短(否则区分度低,大量回表),也不能太长(浪费索引空间、降低写入性能)
SELECT COUNT(DISTINCT LEFT(nickname, 20)) / COUNT(*)
估算区分度,理想值 > 0.9
覆盖索引对
LIKE 'xxx%'
有效,但若查询中包含未建索引的字段(如
SELECT id, email FROM users WHERE nickname LIKE '张%'
),仍需回表

全文索引替代 LIKE 百分号匹配

对描述类、内容类字段(如文章标题、商品详情),

LIKE '%keyword%'
几乎必然慢,应改用
FULLTEXT
索引 +
MATCH ... AGAINST

ALTER TABLE articles ADD FULLTEXT(title, content);
SELECT * FROM articles WHERE MATCH(title, content) AGAINST('数据库优化' IN NATURAL LANGUAGE MODE);

注意点:

仅 MyISAM 和 InnoDB 支持,InnoDB 要求 MySQL ≥ 5.6 默认忽略少于 4 字符的词(
ft_min_word_len
),中文需配合
ngram
插件或使用第三方方案(如 Elasticsearch)
AGAINST('xxx*' IN BOOLEAN MODE)
支持右截断(类似
LIKE 'xxx%'
),但不支持左截断

避免隐式类型转换导致索引失效

一个常被忽略的坑:

LIKE
字段类型与参数类型不一致时,MySQL 可能自动转换,导致索引失效。例如:

phone VARCHAR(20)
有索引,但写成
WHERE phone LIKE 138%
(数字字面量),MySQL 会把
phone
转成数字比较,索引失效
正确写法是
WHERE phone LIKE '138%'
,确保两边都是字符串
同理,
COLLATE
不一致(如字段是
utf8mb4_0900_as_cs
,参数没指定)也可能触发隐式转换

执行前务必用

EXPLAIN
看一眼
key
rows
,哪怕语句看起来“应该能走索引”。很多慢查就卡在这类细节上。

相关推荐