key_len是MySQL实际使用的索引字节数,可精准判断联合索引用了多少列:如索引(status,create_time,user_id),各列非空且类型为TINYINT(1)、DATETIME(5)、BIGINT(8),则key_len=1表示仅用第1列,=6表示用了前2列,=14表示3列全用。

explain 的 key_len 值怎么看出用了几列索引
真正判断联合索引用了多少列,不看 key 字段是否非空,而要看 key_len。这个值是 MySQL 实际用到的索引字节数,它能反推出匹配到了哪几列。
比如联合索引 INDEX(status, create_time, user_id),假设各字段类型为:status TINYINT(1 字节)、create_time DATETIME(5 字节,5.6.4+ 默认精度下)、user_id BIGINT(8 字节),且都非 NULL:
- 查询
WHERE status = 1→key_len = 1 - 查询
WHERE status = 1 AND create_time > '2024-01-01'→key_len = 6(1 + 5) - 查询
WHERE status = 1 AND create_time = '2024-01-01' AND user_id = 100→key_len = 14(1 + 5 + 8)
注意:NULL 列会额外占用 1 字节标记位;变长字段(如 VARCHAR)还要算上长度前缀(1 或 2 字节)。key_len 不是“估算”,它是执行计划中唯一可量化的索引列使用证据。
为什么 WHERE a = 1 AND c = 3 只走第一列,但 EXPLAIN 显示 type=ref
看起来矛盾,其实不冲突——type=ref 表示走了索引定位,但只靠 a 列完成;c 列根本没参与 B+ 树查找,只是在索引叶子节点里做 ICP(Index Condition Pushdown)过滤。
这种场景下容易误判“索引全用了”,实际性能瓶颈可能藏在大量回表或 ICP 过滤开销里。验证方式有二:
- 看
key_len是否包含c列字节数(通常不包含) - 开启
optimizer_trace,查used_condition_pushdown字段是否为true
ICP 是优化,不是索引能力延伸;它发生在引擎层,不能减少扫描的索引范围,只能减少回表次数。
ORDER BY 和 GROUP BY 怎么暴露最左前缀断点
排序和分组不走 WHERE 条件,但它们对索引有序性的依赖更敏感,是检验最左前缀是否“连贯”的试金石。
以索引 (a, b, c) 为例:
-
ORDER BY a, b→ 走索引,Extra无Using filesort -
ORDER BY a, c→ 触发Using filesort,因为b缺失,c在索引中无序 -
ORDER BY b, c→ 必然Using filesort,跳过最左列 -
GROUP BY a, b, c→ 若无聚合函数,可能走索引去重;但GROUP BY b, c就完全失效
关键点:只要 ORDER BY 或 GROUP BY 的列顺序/覆盖不满足索引定义的连续最左前缀,就无法利用索引有序性,优化器会直接放弃。
哪些操作会悄悄截断最左前缀链
不是只有 WHERE 里的 > 或 LIKE '%xxx' 才会中断,这些也常被忽略:
-
IS NOT NULL对非索引首列(如WHERE a = 1 AND b IS NOT NULL)→b不参与定位(MySQL 8.0+ 仍不支持) -
OR条件拆分后,若任一分支不满足最左前缀,整个索引可能退化(如WHERE a = 1 OR b = 2,后者无法走索引) - 对索引列使用函数或表达式:
WHERE YEAR(create_time) = 2024→create_time列失效,即使它是第二列 -
!=或在首列上也会让后续列失效(如WHERE a != 1 AND b = 2,b不走索引)
最左前缀不是“语法检查”,而是 B+ 树物理结构决定的硬约束。任何破坏字典序连续性的操作,都会让右侧列失去定位价值——这点在慢查分析时最容易被绕过。


















