java面试必问16:最左前缀原则:复合索引的灵魂,一点就懂

张开发
2026/4/21 22:30:56 15 分钟阅读

分享文章

java面试必问16:最左前缀原则:复合索引的灵魂,一点就懂
最左前缀原则复合索引的灵魂一篇讲透面试官“复合索引 (a, b, c)查询条件WHERE b 1 AND c 2能用索引吗”你“不能因为跳过了最左列 a索引失效。”面试官“那WHERE a 1 AND c 2呢”你“只能用到 ac 无法使用索引因为中间跳过了 b。”面试官“为什么会有这个原则”你“……”很多人能背出“最左前缀”但一追问“为什么”“如何优化”就含糊了。本文从 BTree 结构出发讲透复合索引的匹配规则和优化技巧。一、什么是最左前缀原则最左前缀原则复合索引联合索引使用时必须从索引的最左列开始匹配不能跳过中间的列。只有遵守这个顺序索引才能充分发挥作用。以复合索引(a, b, c)为例它能有效支持的查询条件模式有a ?a ? AND b ?a ? AND b ? AND c ?不能有效使用索引的情况b ?缺少最左列 ac ?缺少 a、ba ? AND c ?跳过 b只能用 ac 无法走索引注意WHERE a ? AND c ?并不是完全不能用索引而是只能用(a)部分过滤c的条件无法在索引中直接定位需要回表后再过滤。二、为什么会有最左前缀原则—— BTree 的结构决定复合索引在 BTree 中的排序规则是先按第一列排序第一列相同再按第二列排序以此类推。例如索引(name, age)存储的数据逻辑顺序nameage张三20张三25李四18李四22王五30可以看到所有name相同的记录是连续存放的。在name相同的前提下age是有序的。但如果只按age搜索比如age 20age在整个索引中并不是全局有序的20 出现在不同 name 段中因此无法使用索引快速定位。结论索引的有序性是基于最前列建立的跳过了最前列后续列的有序性就失去了意义。三、哪些情况能用到索引假设索引(a, b, c)以下查询都能有效利用索引查询条件索引使用情况a 1✅ 完全使用索引a 1 AND b 2✅ 使用 a、ba 1 AND b 2 AND c 3✅ 使用 a、b、ca 1 AND c 3⚠️ 只用到 ac 无法使用但 a 可过滤a 1 AND b 2 AND c 3⚠️ 用到 a 和 b范围查询后 c 无法使用a IN (1,2) AND b 2✅ 用到 a 和 bIN 相当于多个等值a 1 ORDER BY b✅ 索引已排序避免 filesorta 1 AND b 2 ORDER BY c✅ 索引有序无需额外排序四、哪些情况索引失效或效率下降查询条件原因b 2缺少最左列 ac 3缺少 a、ba 1 AND c 3跳过 bc 无法走索引a 1 AND b 2范围查询后 b 无法使用a 后的列全部失效a 1 OR b 2OR 前后未全索引除非 a 和 b 分别有索引特别说明a 1 AND b 2中a 是范围查询b 的条件无法在索引中直接定位因为索引在 a 范围内b 不是有序的a 不同b 可能乱序。优化器只能用到 a 的过滤b 需要回表后过滤。五、如何设计高效的复合索引1. 区分度高的列放在左边将筛选能力最强的列放在最左可以快速缩小数据范围。例如(status, create_time)比(create_time, status)更好如果 status 只有几个值则 create_time 更合适。2. 等值查询的列放在左边范围查询的列放在右边WHERE a 1 AND b 2 AND c 3索引(a, b, c)中b 是范围查询导致 c 无法使用。可以调整索引为(a, c, b)如果 c 是等值查询可以先过滤。3. 将经常排序的列加入索引如果经常ORDER BY b且WHERE a 1索引(a, b)可以避免 filesort。4. 覆盖索引优先尽量让索引包含查询所需的所有列避免回表。例如SELECT a, b FROM t WHERE a 1索引(a, b)就是覆盖索引。六、常见面试追问Q1WHERE a 1 AND c 2完全不能用索引吗不是完全不能用。MySQL 可以使用索引的(a)部分过滤但c无法在索引中定位。优化器可能选择使用索引如果 a 的区分度高然后回表再过滤 c也可能直接全表扫描如果 a 的区分度低。Q2WHERE a IN (1,2) AND b 3能用索引吗能。IN相当于多个等值MySQL 会分别对每个值使用索引。执行计划中type通常为range。Q3WHERE a 1 AND b 2 ORDER BY c能避免排序吗可以。因为索引(a, b, c)已经按 a、b、c 排序ORDER BY c是在 a1 且 b2 的范围内c 自然有序无需 filesort。Q4如果查询条件是WHERE a 1 AND a 10 AND b 2如何优化范围查询a会导致 b 无法使用。可以考虑将 b 放在前面索引(b, a)先等值 b再范围 a。或者使用IN改写如果 a 的值可枚举。Q5复合索引最多可以包含多少列MySQL 限制最多 16 列但实际建议不超过 5 列否则维护成本高且区分度可能下降。七、总结索引(a,b,c)查询条件索引使用情况a1✅ 全用a1 AND b2✅ 全用a1 AND b2 AND c3✅ 全用a1 AND c2⚠️ 只用 ab2❌ 失效a1 AND b2⚠️ 只用 a范围后失效a1 AND b2 AND c3⚠️ 用 a、bc 失效一句话记住最左前缀最左先等值前范围后全失效。理解最左前缀原则是设计高效复合索引的基础。在日常开发中分析查询模式将最常用的等值条件放在索引左侧范围条件放在右侧能显著提升查询性能。希望这篇文章能帮你彻底掌握这个高频考点欢迎继续讨论。

更多文章