MySQL中LIKE '%张%'未走索引,因前导通配符破坏B+树有序性,EXPLAIN显示type=ALL、key=NULL即证实优化器放弃索引;后缀模糊LIKE '张%'可走索引,但受字段长度、排序规则及函数包裹影响。

LIKE查询没走索引,先看EXPLAIN的type和key
执行EXPLAIN SELECT * FROM users WHERE name LIKE '%张%',如果type是ALL、key是NULL,说明根本没用索引——这不是Navicat的问题,是MySQL优化器直接放弃索引扫描。前导通配符(%开头)会让B+树索引失效,这是底层机制决定的,不是配置能绕过的。
后缀模糊(LIKE '张%')能走索引,但要注意字段类型和排序规则
当写成name LIKE '张%'时,理论上可走name上的普通索引。但实际常踩坑:
- 字段用了
VARCHAR但定义长度远超实际(如VARCHAR(255)存昵称),可能导致索引选择性低,优化器主动跳过 -
name列的COLLATE和WHERE中字面量不一致,比如列是utf8mb4_0900_ai_ci,而查询里隐式转成utf8mb4_general_ci,就会触发全表扫描 - 条件里混用了函数,例如
UPPER(name) LIKE UPPER('张%'),哪怕name有索引也无效
想加速%中间%类查询,别只盯着LIKE,得换思路
对LIKE '%关键词%'这种场景,硬靠B+树索引没解。可行路径只有三条:
- 改用全文索引:
ALTER TABLE users ADD FULLTEXT(name),再用MATCH(name) AGAINST('张' IN NATURAL LANGUAGE MODE)——但要求字段是CHAR/VARCHAR/TEXT,且最小词长默认4,短词需调ft_min_word_len - 加生成列+函数索引(MySQL 8.0.13+):
ALTER TABLE users ADD COLUMN name_reverse VARCHAR(64) STORED AS (REVERSE(name)),再建索引CREATE INDEX idx_name_reverse ON users(name_reverse),查REVERSE(name) LIKE REVERSE('%张%')就等价于后缀匹配 - 业务层预处理:比如用户搜索“张三”,提前把“张三”“三张”“张”“三”都落库到一个
search_tokens辅助表,用等值JOIN代替模糊匹配
Navicat里看执行计划,别信rows估算值
Navicat导出的执行计划CSV里rows列只是优化器估算,受统计信息陈旧、采样偏差影响极大。同一语句两次执行,rows差10倍不奇怪。真正要盯的是:type有没有从range退化成ALL、key是不是从索引名变成NULL、Extra里有没有Using filesort或Using temporary——这些才是硬指标。











