like 'abc%' 能走索引是因为b+树支持最左前缀匹配,等价于范围查询 name >= 'abc' 且 name
LIKE 'abc%' 查询为什么能走索引?
因为 MySQL 的 B+ 树索引支持最左前缀匹配,
WHERE name LIKE 'abc%'等价于查找所有name >= 'abc'且name 的记录,优化器能直接定位索引区间,避免全表扫描。但前提是:
name字段上必须有索引,且不能被函数包裹(如UPPER(name) LIKE 'ABC%'会彻底失效);也不能出现在联合索引的非最左位置(比如索引是(status, name),单独查name LIKE 'abc%'就用不上)。
- 执行前务必用
EXPLAIN验证:type应为range或ref,key显示索引名,rows明显小于总行数- 如果字段是
VARCHAR(255)但平均值才 12 字符,可建前缀索引(如INDEX(name(12)))减小索引体积,提升写入和缓存效率- 区分度过低时(如
name LIKE 'a%'匹配超 25% 行),优化器可能主动放弃索引——用SELECT COUNT(*) FROM t WHERE name LIKE 'a%'先估算比例怎么用覆盖索引避免回表?
即使
name LIKE 'abc%'走了索引,若SELECT *还是要回主键索引捞完整行数据,I/O 开销仍大。覆盖索引就是把查询需要的所有字段都塞进索引里,让 MySQL 直接从索引页返回结果。例如常查
id、name、created_at,就建:CREATE INDEX idx_name_cover ON users (name, id, created_at);
- 注意字段顺序:
name必须放最左(满足前缀匹配),后面跟查询中SELECT和WHERE涉及的字段- 覆盖索引对
ORDER BY name也有效,但ORDER BY created_at就不行(不满足最左前缀)- 别盲目加太多字段:索引变大 → 写入变慢、内存占用高 → 可能挤掉其他热数据页
为什么加了索引还是慢?常见坑点
索引建了,
EXPLAIN也显示用了,但查询延迟没降多少——大概率掉进了这些隐性陷阱:
- 字符集或排序规则不一致:比如
name是utf8mb4_0900_as_cs,而查询字面量'abc'默认按连接字符集解析,触发隐式转换,索引失效。用SELECT COLLATION('abc')和SELECT COLLATION(name)对比确认- 字段上有空值或大量重复前缀:比如 10 万用户昵称都以 “user_” 开头,
LIKE 'user_%'实际扫描行数仍巨大,此时索引收益极低- 查询带
OR或子查询:哪怕其中一部分能走索引,整体执行计划也可能退化为全表扫描- MySQL 版本低于 5.6:旧版本对覆盖索引支持不完善,
Using index在Extra列不一定稳定出现要不要用函数索引替代普通索引?
MySQL 8.0+ 支持函数索引,比如想统一忽略大小写搜索:
CREATE INDEX idx_name_lower ON users ((LOWER(name)));,然后查WHERE LOWER(name) LIKE 'abc%'就能走索引。但函数索引不是银弹:
- 必须确保查询中的函数调用与索引定义**完全一致**(包括括号、空格、嵌套层级),少个括号都不行
- 函数索引无法用于
ORDER BY或GROUP BY排序/分组(除非表达式完全匹配)- 更稳妥的做法仍是写入时预计算:新增
name_lower字段,INSERT/UPDATE时同步填充,再对它建普通索引真正容易被忽略的是:覆盖索引只对「固定前缀 + 后缀通配」生效,一旦业务要求变成「包含某词」或「以某词结尾」,就得立刻跳出索引思维——要么换全文索引,要么在应用层加缓存或引入搜索引擎,而不是继续堆索引字段。












