1015 字
约 3 分钟
7
S11-J02 · 索引失效的六种情况
适用读者:明明加了索引却还是慢的人。
前置:S11-B05、S11-J01。
实测环境:MySQL 8.0.46(s11lab,20,000 行,2026-11-05)。
覆盖旧文:1233(51) 853(98) 850(105) 1542(100) = 354 点。
覆盖扩展:E-S11-015(隐式转换的方向)、E-S11-016(OR 与索引合并)。
上一篇:S11-J01 · 回表与覆盖索引
下一篇:S11-J03 · Explain 逐列读。
1. 一句话结论
索引失效的本质是"优化器无法用索引的有序性快速定位"——函数包裹、前导模糊、类型转换、OR 混用、联合索引跳列、选择性太低。
2. 实测对照表(同一张表,同一批数据)
| # | SQL | type | key | rows | 结论 |
|---|---|---|---|---|---|
| 1 | where age=30 |
ref | idx_age | 250 | ✅ 正常 |
| 2 | where age+1=31 |
ALL | NULL | 20000 | ❌ 函数包裹 |
| 3 | where age='30' |
ref | idx_age | 250 | ✅ 字符串常量会被转成数字 |
| 4 | where name like 'u1%' |
range | idx_name | 9848 | ✅ 前缀可用 |
| 5 | where name like '%u1%' |
index | idx_name | 19697 | ⚠️ 全索引扫描(非 range) |
| 6 | where age=30 or city='city5' |
ALL | NULL | 19697 | ❌ OR 混无索引列 |
最震撼的一行是 #2:同一个条件,写法不同,扫描行数 250 → 20000(80 倍)。
3. 六种失效与边界
| 情况 | 为什么 | 例外/边界 |
|---|---|---|
| ① 列上做运算/函数 | 索引存的是原值 | 8.0 的函数索引((col+1) 建索引)可解 |
② 前导模糊 %x |
无法有序定位 | 仍可走覆盖索引扫描(#5 的 type=index) |
| ③ 隐式类型转换 | 转换发生在列上才失效 | #3 中字符串常量被转成数字 → 不失效 |
④ OR 混无索引列 |
只能全表 | 两侧都有索引 → 可能 index_merge |
| ⑤ 联合索引跳最左列 | 无法定位 | 8.0 有 skip scan(条件有限) |
| ⑥ 选择性太低 | 优化器判定全表更快 | 强制 force index 可验证 |
第 ③ 条最容易误判:"字符串 vs 数字"谁被转换,决定是否失效——where phone='138...'(列是 varchar)不失效;where varchar_col = 138(列被转数字)失效。
4. OR 的正确写法(E-S11-016)
-- ❌ city 无索引 → 全表
where age=30 or city='city5'
-- ✅ 两边都建索引(可能 index_merge)
where age=30 or city2='city5' -- city2 有索引
判据:"OR 两侧的列都有索引吗?" 没有 → 改写为 UNION ALL。
5. 怎么验证"到底用没用索引"
| 手段 | 说明 |
|---|---|
EXPLAIN |
看 type/key/rows |
EXPLAIN ANALYZE(8.0.18+) |
看实际执行时间与行数 |
force index / ignore index |
强制对比 |
慢日志 Rows_examined |
线上真实指标 |
判据:"rows 与返回行数差多少倍?" 差得多 → 索引没发挥作用。
6. 五个误区
| 误区 | 真相 |
|---|---|
| "加了索引就一定会用" | 六种情况都会失效 |
"like '%x%' 完全不用索引" |
可走覆盖索引扫描(但收益小) |
| "隐式转换一定失效" | 取决于转换发生在哪一侧 |
"OR 一定全表" |
两侧都有索引可用 index_merge |
| "优化器总选最优" | 统计信息过期会选错 |
7. 自检
- 六种失效的根因分别是什么(一句话)?
- 实测里函数包裹让 rows 从多少变到多少?
- 隐式转换"什么时候失效"?
like '%x%'的type=index是什么意思?- 怎么验证"索引到底有没有用上"?
8. 下一篇
S11-J03 · Explain 逐列读
失效讲完,下一篇把 EXPLAIN 的每一列读懂:type 的等级、rows 的估算逻辑、Extra 的十几种值。
本篇属于系列《S11 · 数据库与 SQL》。旧文来源:A-1233/853/850/1542;扩展点 E-S11-015/016。六组对照为 MySQL 8.0.46 实测。
S11-J02 · 索引失效的六种情况
https://www.clxhxhhr.top/posts/5332/ 评论
0 条
还没有评论,先写一条吧。