
MySQL索引失效面试答不上怎么办?5个扣分点让面试官相信你会排查
这期拆解 MySQL 索引失效面试的 5 个高频扣分点:如何看 EXPLAIN、判断复合索引顺序、解释范围条件和 LIKE 边界,并把答案落到可验证的排查路径上。
面试官问「为什么这个 SQL 没走索引」,最怕的不是你忘了某条口诀,而是你只会背「不要在字段上用函数、不要左模糊、遵守最左前缀」。这些话没错,但面试官真正想听的是:你能不能拿一条慢 SQL,从执行计划里判断问题在哪里,再说出改索引、改条件、改查询顺序的理由。
一句话先记住:索引失效题不要答成禁忌清单,要答成排查路径。先看
EXPLAIN,再判断索引有没有被选中、用了几列、扫了多少行,最后把改法落到业务查询条件上。先把索引失效的判断逻辑讲清楚
MySQL 文档对索引的作用说得很直白:没有索引时,MySQL 需要从第一行开始顺序读取;有合适索引时,它可以更快定位到相关行,而不用把整张表读一遍。1
所以面试里的「索引失效」通常不是一句「索引完全没用了」就能讲完。更准确地说,它可能有 4 种情况:
| 现场现象 | 你该怎么解释 | 面试官在看什么 |
|---|---|---|
key 是 NULL | 优化器没有选中可用索引,要回到 WHERE 条件和索引定义检查 | 你会不会看执行计划 |
key 有值,但 key_len 很短 | 只用了复合索引的一部分,后面的列没有参与定位 | 你是否理解复合索引顺序 |
type 是 range 或 index | 可能不是点查,而是在扫一段索引或整棵索引 | 你能不能区分「走索引」和「高效」 |
rows 很大、filtered 很低 | 预估要检查很多行,再靠条件过滤 | 你会不会看扫描量和过滤比例 |
MySQL 的
EXPLAIN 会给出 possible_keys、key、key_len、rows、filtered、type、Extra 等字段;其中 key 表示实际选择的索引,key_len 能帮助判断复合索引用到了多长的前缀,rows 是预估检查行数,filtered 是按表条件过滤后的预估比例。2这就是你回答的主线:不是背「哪些写法会失效」,而是解释「为什么优化器只能这样扫」。
扣分点 1:把「建了索引」等同于「一定会走索引」
很多人一上来就说:「这个字段有索引,所以应该能走。」这句话很危险。MySQL 文档明确提到,如果有多个索引可选,优化器通常会选择能找到最少行的那个索引;当查询要访问大部分行时,顺序读取反而可能比通过索引读更快。1
面试官问你「为什么没走索引」时,你可以先这样答:
我不会先假设它一定该走某个索引。我会先看EXPLAIN:possible_keys说明理论候选索引,key说明实际选中的索引。如果possible_keys有值但key是NULL,说明优化器评估后没有选;如果key有值,还要继续看type、key_len、rows和Extra,判断它是不是高效使用。
这段话比「建索引就行」更像真实排查。它把问题从口诀拉回执行计划。
举个简单场景:
CREATE INDEX idx_status ON orders(status);
SELECT *
FROM orders
WHERE status IN ('paid', 'shipped', 'closed');如果订单表里绝大多数行都属于这几个状态,优化器不一定认为
idx_status 值得用。你不能只说「索引失效了」,更应该说:这个条件区分度低,可能需要结合其他高选择性条件,或者接受它本来就不是一个适合单列索引解决的问题。扣分点 2:只会背最左前缀,说不清复合索引顺序
复合索引题最常见的扣分点,是把「最左前缀」背成一句口号。
MySQL 文档说,复合索引可以用于测试所有索引列的查询,也可以用于只测试第一列、前两列、前三列的查询;如果索引是
(col1, col2, col3),可用于 (col1)、(col1, col2)、(col1, col2, col3) 这样的左侧前缀。3 反过来,只查 (col2) 或 (col2, col3),并不构成这个索引的左侧前缀,不能用它做查找。3面试里不要只说「遵守最左前缀」,要把它翻译成业务顺序:
CREATE INDEX idx_user_status_time ON orders(user_id, status, created_at);
SELECT *
FROM orders
WHERE user_id = 1001
AND status = 'paid'
AND created_at >= '2026-07-01';这类索引顺序比较合理,因为
user_id 和 status 是等值条件,created_at 是范围条件。你的回答可以这样组织:我会把高频等值过滤条件放在复合索引前面,再把范围或排序字段放在后面。这样查询可以先定位到某个用户、某类订单,再在时间范围里扫描。如果索引写成(created_at, user_id, status),它可能先按时间扫一段,再过滤用户和状态,扫描量会变大。
注意这里不要说得太绝对。真实数据库还会受数据分布、统计信息、查询列和排序需求影响。面试里你要让对方听到的是:你知道索引顺序不是玄学,它要服务最常见的查询条件。
扣分点 3:范围条件后面的列还当成精确定位条件
这是复合索引题里最容易被追问的地方。
MySQL 的范围优化文档说明,在 BTREE 复合索引上,优化器会尽量使用更多 key part 来确定区间;但当某个 key part 使用
>、<、>=、<=、BETWEEN、!=、LIKE 等范围类操作符时,它会使用这个操作符确定区间,但不再继续用后续 key part 构造这个区间。4把这句话放进面试场景,就是:
CREATE INDEX idx_user_time_status ON orders(user_id, created_at, status);
SELECT *
FROM orders
WHERE user_id = 1001
AND created_at >= '2026-07-01'
AND status = 'paid';这条 SQL 看起来三个字段都在索引里,但
created_at >= ... 是范围条件。它可能只能先定位 user_id,再扫 created_at 的一段区间,status 更像是在这段结果里继续过滤,而不是继续精确缩小索引区间。更适合的索引可能是:
CREATE INDEX idx_user_status_time ON orders(user_id, status, created_at);面试里可以这样说:
如果查询固定是「某个用户 + 某个状态 + 时间范围」,我会优先考虑(user_id, status, created_at)。因为前两列是等值条件,能先缩小范围;时间字段放到后面做范围扫描。原来的(user_id, created_at, status)不是完全没用,但status很可能不能继续参与区间定位。
这段回答的重点不是背「范围后失效」四个字,而是说清楚「后续列为什么只能过滤,不能继续帮你定位」。
扣分点 4:把 LIKE 只答成「模糊查询不走索引」
LIKE 题也不能答得太粗。MySQL 范围优化文档里有一个边界:对 BTREE 索引来说,
LIKE 'ab%' 这种不以通配符开头的常量模式可以形成范围条件;但类似 LIKE '%b' 的条件不能用于构造范围扫描,文档示例里它会在提取范围条件时被移除。4所以面试里别说「
LIKE 都不走索引」,要分清两类:| 写法 | 面试解释 | 更好的表述 |
|---|---|---|
name LIKE 'zhang%' | 前缀固定,可以按索引有序性定位一段范围 | 可能走范围扫描,但还要看数据量和执行计划 4 |
name LIKE '%zhang' | 左侧不固定,无法从索引开头确定范围 | 通常不能靠普通 BTREE 索引做高效查找 4 |
LOWER(name) = 'zhang' | 对列做函数,普通索引列值不再直接参与比较 | 要考虑改写条件、增加规范化字段或函数索引,具体看数据库版本和业务约束 |
如果被追问「那怎么改」,不要只说「去掉百分号」。你可以给出更工程化的回答:
如果业务需要前缀搜索,比如按手机号、订单号前缀查,可以把输入限制成右模糊,并配合合适索引。如果业务必须支持任意包含搜索,普通 BTREE 索引不适合硬扛,要考虑搜索引擎、倒排索引、额外冗余字段,或者先用更强的结构化条件缩小范围。
这样答,面试官能听出来你知道 SQL 写法和产品需求之间有边界。
扣分点 5:看到 ALL 就只会说「加索引」
但面试里只说「加索引」还不够。你要继续看三件事:
rows预估是不是很大。filtered是不是很低。WHERE里的条件能不能改成适合索引的形式。
MySQL 文档对
rows 和 filtered 的解释是:rows 表示预计要检查的行数,InnoDB 下它是估算值;filtered 表示按表条件过滤后的估计比例,rows × filtered 可以估算和下一张表连接的行数。2你可以按这个顺序答:
我会先确认这是不是一个真的慢查询。如果表很小,ALL未必值得优化;如果rows很大、filtered很低,就说明扫描量和过滤效率都有问题。接着我会看条件是否命中了复合索引左侧前缀,有没有函数、隐式类型转换、左模糊、低区分度字段单独建索引这些问题。最后再决定是改 SQL、改索引顺序,还是调整业务查询入口。
这段话比「加索引」更稳,因为它承认执行计划是估算,也承认索引不是万能药。
一段可以直接练的 90 秒回答
假设面试官给你这条 SQL:
CREATE INDEX idx_user_time_status ON orders(user_id, created_at, status);
SELECT *
FROM orders
WHERE user_id = 1001
AND status = 'paid'
AND created_at BETWEEN '2026-07-01' AND '2026-07-31';你可以这样答:
我会先跑EXPLAIN,看possible_keys、key、key_len、type、rows和filtered。如果实际用了idx_user_time_status,但key_len显示只用到user_id和created_at这一段,我会怀疑status没有继续参与索引区间定位。 原因是这个复合索引顺序是(user_id, created_at, status),created_at BETWEEN ...是范围条件。MySQL 在复合索引上遇到范围条件后,后面的列通常不能继续用来构造更窄的区间,只能在扫出来的范围里过滤。 如果这个查询是高频入口,我会考虑把索引改成(user_id, status, created_at)。这样先按用户和状态做等值过滤,再按时间范围扫描。改完之后还要重新看EXPLAIN,确认rows是否下降、key_len是否更符合预期,不能只凭改了索引就宣布优化完成。
这段回答有三个好处:先说排查工具,再说索引原理,最后说验证方式。面试官继续问「为什么」时,你还有东西可展开。
准备时按这张清单检查
技术面试前,不要准备一堆「索引失效八股」原文。你只需要把每个点都练成「现象、原因、改法、验证」四句话。
| 自查问题 | 合格回答应该包含什么 |
|---|---|
| 什么叫索引失效? | 不是泛泛说「没走索引」,而是能结合 EXPLAIN 看 key、key_len、type、rows、filtered |
| 复合索引怎么判断? | 能说清左侧前缀,能用 (a,b,c) 举出哪些查询能用、哪些不能用 |
| 范围条件为什么危险? | 能解释范围列之后的列可能不再参与区间定位,而不是只背「范围后失效」 |
LIKE 怎么答? | 能区分 abc% 和 %abc,知道前缀模式与左模糊不是一回事 |
| 看到全表扫描怎么办? | 先判断扫描量和过滤比例,再决定改条件、改索引还是接受这个查询形态 |
| 怎么证明优化有效? | 改完再看 EXPLAIN,必要时对比真实耗时、慢日志和线上数据分布 |
最后再删掉这 5 句话:
- 「这个字段有索引,所以一定能走。」
- 「索引失效就是因为没遵守最左前缀。」
- 「范围查询后面的字段都没用了。」
- 「
LIKE查询一定不走索引。」 - 「看到全表扫描就加索引。」
这些话的问题不是完全错,而是太粗。真实面试里,粗话术最容易被追问穿。你要把答案落到执行计划、复合索引顺序和改完后的验证上,面试官才会相信你不是只背过索引口诀。
相似内容
- 登录后可发表评论。
