当前位置: 首页 > news >正文

【大白话说Java面试题 第78题】【Mysql篇】第8题:解释下最左前缀原则?

第8题:解释下最左前缀原则

📚回答:

  • 核心考点
    大厂面试要求不仅知道“查询必须从最左列开始”,更要深入理解底层B+树排序原理范围查询导致后续列失效的机制跳过列时索引下推的工作方式,以及如何设计联合索引顺序。面试官常追问:“最左前缀一定需要最左列吗?为什么?”

1. 最左前缀原则的定义

最左前缀原则是指:对于联合索引,MySQL会从索引的最左列开始匹配查询条件,只有满足最左前缀的查询才能利用该索引加速检索。

联合索引的本质:联合索引(a, b, c)相当于创建了三个索引:

  • 一个按a排序的索引
  • 一个按(a, b)排序的索引
  • 一个按(a, b, c)排序的索引

因此,(a, b, c)这个联合索引可以用于匹配(a)(a, b)(a, b, c)的查询条件,但不能用于匹配(b)(c)的查询。

2. 联合索引的B+树排序原理(深入理解)

为什么必须从最左列开始?

把联合索引想象成一个电话本

  • 电话本先按姓氏排序,姓氏相同再按名字排序
  • 要查找“所有叫小明的人”(只给名字),你无法直接翻到那一页,因为电话本不是按名字排的
  • 必须先定位到姓氏,才能在姓氏内部找到名字

联合索引(a, b, c)的B+树排序规则

  • 先按a排序
  • a相同时,按b排序
  • ab都相同时,按c排序

这就是为什么查询条件必须包含最左列——没有最左列a,索引的B+树就无法定位起始搜索位置,只能全索引扫描甚至全表扫描。

3. 命中规则速查表

以联合索引(a, b, c)为例:

WHERE条件是否命中使用哪些列说明
WHERE a = 1✅ 完全命中a匹配最左列
WHERE a = 1 AND b = 2✅ 完全命中a, b匹配最左两列
WHERE a = 1 AND b = 2 AND c = 3✅ 完全命中a, b, c匹配所有列
WHERE a = 1 AND c = 3⚠️ 部分命中ac用ICP)跳过bc无法用于索引范围查找
WHERE b = 2❌ 不命中未从最左列开始
WHERE c = 3❌ 不命中未从最左列开始
WHERE b = 2 AND c = 3❌ 不命中未从最左列开始

特殊情况:如果查询条件是WHERE b = 2 AND a = 1,MySQL优化器会自动重排为WHERE a = 1 AND b = 2,能够命中索引。这是因为MySQL的查询优化器会自动调整AND条件顺序,以匹配索引的最左前缀。

4. 跳过中间列的场景:(a, c)能走索引吗?

结论:能部分命中,但c列无法用于索引范围查找。

原理

  • 索引按(a, b, c)顺序排序,数据先按a排,a相同再按b排,b相同再按c
  • WHERE a=1 AND c=3时,MySQL用a=1定位到索引中的一段范围
  • 但由于b没有出现在条件中,无法精确定位到某条记录,索引在b这一层就断了
  • c列在b无序的情况下也处于无序状态,无法用B+树二分查找直接定位到c=3的位置

c的条件还能用吗?——索引下推(ICP)

MySQL 5.6+引入索引下推(Index Condition Pushdown, ICP)

  • 在索引扫描过程中,对索引中包含的字段先做判断,提前过滤掉不满足条件的记录
  • 对于WHERE a=1 AND c=3,会在索引层用c=3过滤掉部分数据,减少回表次数
  • c仍然无法用于索引范围查找(即无法像a那样用二分查找快速定位)
5. 范围查询:为什么>后面的列索引会失效?

结论:范围查询(><BETWEENLIKE 'xxx%')之后的索引列全部失效。

原因

  • 索引是按顺序排列的。等值查询能精确定位到某个节点,后续列可以继续在该节点下排序查找
  • 但范围查询返回的是一段区间,这段区间内后续列的值是无序的
  • 例如WHERE a=1 AND b>20 AND c=3,在a=1b>20的区间内,c的值不是有序的,无法用索引快速定位c=3

关键区分

  • 等值查询=IN(可优化器重排),后续列可以继续用索引
  • 范围查询><BETWEENLIKE 'xxx%',后面的列索引失效
6. 设计联合索引顺序的黄金法则

铁律1:等值查询列放前面,范围查询列放后面

-- 查询条件WHEREuser_id=123ANDorder_date>'2026-01-01'-- 正确设计:索引(user_id, order_date)-- user_id等值精确定位 → order_date范围查找CREATEINDEXidx_user_dateONorders(user_id,order_date);-- 错误设计:索引(order_date, user_id)-- order_date范围后,user_id无法用索引

铁律2:高区分度列放前面

-- 错误:status只有3个值,区分度极低,放最左CREATEINDEXidx_wrong(status,user_id);-- 正确:user_id有1万个不同值,区分度高,放最左CREATEINDEXidx_right(user_id,status);

对比:100万行数据,status=2匹配约33万行(全表33%),user_id=10086匹配约100行(0.01%)

铁律3:如果有ORDER BY,把排序列放最后

-- 查询WHEREuser_id=123ORDERBYcreate_timeDESC-- 索引(user_id, create_time)-- 既能快速过滤user_id,又能让create_time天然有序,避免filesort

铁律4:通过调整顺序减少索引数量

由于支持最左前缀,有了(a, b)索引后,一般不需要再单独建(a)索引。

7. 常见错误 vs 正确做法
错误写法为什么错正确做法
WHERE a > 1 AND b = 2,建索引(a, b)范围a放左边,b等值失效建索引(b, a),等值放前
WHERE a = 1 AND c = 3,建索引(a, b, c)跳过bc无法索引查找b无条件,可建(a, c)或接受ICP
WHERE a = 1 AND b > 2 AND c = 3,建索引(a, b, c)b范围后c失效建索引(a, c, b),把cb
ORDER BY b,索引是(a, b)a无条件不满足最左前缀,ORDER BY无法用索引建索引(b)或给查询加a条件
低基数列放最左(如status区分度极低,扫描大量数据高区分度列放最左
8. 面试官追问与高分回答

Q1:最左前缀原则的底层原理是什么?

A:联合索引在B+树中按从左到右的顺序排序存储。先按第一列排序,第一列相同再按第二列排序,依此类推。这种存储结构决定了:只有从最左列开始的连续列才能利用索引的有序性进行二分查找。跳过最左列,MySQL无法定位起始位置。

Q2:WHERE a = 1 AND c = 3能走索引(a, b, c)吗?c的条件有用吗?

A:能部分命中——a可以用于索引查找。c的条件在MySQL 5.6+中通过**索引下推(ICP)**在索引层提前过滤,减少回表次数。但c无法用于索引范围查找(即不能用B+树的二分查找直接定位c=3的位置),因为跳过了bca=1的范围内是无序的。

Q3:为什么范围查询后面的列索引会失效?

A:等值查询能精确定位到B+树中的某个节点,后续列在该节点下仍然有序。但范围查询返回的是一个区间,这个区间内后续列的值不再有序,无法用索引快速定位。

Q4:联合索引(a, b, c)WHERE a = 1 AND b IN (2,3) AND c = 4能用到所有列吗?

AIN条件在优化器处理中等同于多个等值,不属于范围查询。如果b的值数量可控,索引可以用完(a, b, c)三列。

Q5:设计联合索引时,顺序怎么排?

A:三大原则:①等值查询列放前面,范围查询列放后面;②高区分度列放前面;③有ORDER BY时,排序列放最后。还要考虑索引复用——已有(a, b)可覆盖(a)查询。

9. 实战案例:优化慢查询

场景:订单表几百万行,查询用户123的“已完成”订单,按订单日期倒序,只要前20条。

-- 原SQLSELECT*FROMordersWHEREuser_id=123ANDstatus='已完成'ORDERBYorder_dateDESCLIMIT20;-- 原索引:只有(user_id)-- 问题:过滤user_id后还有5000条,需要逐一过滤status,再排序

优化过程

考虑因素设计决策
等值条件user_idstatus都是等值 → 放前面
排序列order_date→ 放最后
希望不回表如只查(user_id, status, order_date),可用覆盖索引
-- 最终索引ALTERTABLEordersADDINDEXidx_uid_status_date(user_id,status,order_date);

效果:扫描行数从5000降至86,无filesort,速度从几百毫秒降到几毫秒。

10. 总结对比表
查询条件类型索引(a, b, c)的使用情况优化手段
(a)✅ 完全命中a
(a, b)✅ 完全命中a, b
(a, b, c)✅ 完全命中三列
(a, c)⚠️ 仅命中ac用ICPb确实无查询条件,可建(a, c)
(b)❌ 完全不命中b单独建索引
范围后列❌ 范围后的列索引失效调整顺序,范围列放最后
低基数列⚠️ 能命中但效率差高区分度列放最左

💡面试官想要的满分总结

“最左前缀原则的本质是B+树的排序特性——联合索引(a, b, c)按照a、然后b、然后c的顺序排序。查询时必须从最左列开始,才能利用B+树的有序性进行二分查找定位。

命中规则(a)(a, b)(a, b, c)能完全命中;(a, c)只能命中ac可通过MySQL 5.6+的索引下推在索引层过滤,减少回表);(b)完全不命中。

范围查询陷阱:等值查询列放前面,范围查询列放后面。因为范围查询会破坏后续列的有序性,导致索引失效。

设计原则:①等值前列,范围后排;②高区分度列放左;③有ORDER BY时排序列放最后;④利用最左前缀特性,通过调整顺序减少冗余索引。

一句话:最左前缀原则是联合索引的生命线——用对了一飞冲天,用错了等于白建。”

📌PDF:大白话说Java面试题 — 03-Mysql篇

http://www.jsqmd.com/news/905128/

相关文章:

  • 15分钟告别黑苹果配置噩梦:OpCore-Simplify智能向导带你轻松搞定OpenCore EFI
  • 如何为Taotoken API Key设置访问控制与审计规则
  • 如何完全掌控你的微信聊天记录?WeChatMsg本地化处理终极指南
  • Flutter Web + Supabase 构建 AI 家计簿:从原型到全功能模块的实战
  • 2026郑州万象城附近名表回收避坑指南|劳力士/欧米茄/积家变现干货攻略 - 奢侈品回收测评
  • Windows 10终极清理优化指南:如何使用Windows10Debloater快速移除臃肿软件
  • 通达信缠论插件:3分钟让技术分析效率提升90%
  • 北京名包回收高价门店推荐,对比几家门店,这家价最高 - 奢侈品回收测评
  • DesignKit:基于CSS变量与AI协议的开源设计系统,加速原型到代码工作流
  • 移动机器人底盘运动学模型全解析
  • Atlas OS完整指南:三步打造更快速、更隐私的Windows系统
  • 基于LM358与NTC热敏电阻的简易温度报警器设计与实现
  • 合肥好柿科技有限公司(好柿科技)官网、联系方式、官方网站、联系电话、联系地址、抖音账号、公司地址 - 寻茫精选
  • G-Helper终极指南:如何用轻量级工具彻底掌控你的华硕笔记本
  • 告别蓝屏!华硕笔记本Win10改Win7保姆级教程(BIOS设置+GPT转MBR避坑指南)
  • 如何10分钟完成《重返未来:1999》终极自动化助手M9A的专业配置
  • 猫抓插件专业指南:浏览器资源嗅探与媒体下载终极方案
  • 从perf到bpftrace:一文搞懂Linux内核tracepoint的四种花式用法
  • 深圳雅思提分机构排行:5家头部机构实力横向对比 - 互联网科技品牌测评
  • 专业跨平台字体方案:6种字重PingFangSC苹方字体实战指南
  • Arduino蓝牙遥控车制作指南:从硬件选型到代码调试全解析
  • 南通外贸建站推荐,WaiMaoYa 外贸鸭一站式全包服务,零基础也能做好外贸建站 - 外贸独立站运营
  • ppf-contact-solver行业应用:汽车、航空和医疗领域的潜在用途
  • 电路设计入门:从欧姆定律到PCB实战,手把手教你制作自动小夜灯
  • 如何永久保存微信聊天记录:5步完整使用WeChatMsg终极指南
  • Sora 2 3D空间一致性失效的7种典型崩溃场景(含OpenUSD兼容性故障日志与热修复补丁)
  • 深圳5家正规雅思培训机构实测排行 基于核心教学指标 - 互联网科技品牌测评
  • Teachable Machine:零代码AI训练神器,让每个人都能成为机器学习创造者
  • Deep-Live-Cam实时换脸终极指南:解决inswapper_128_fp16.onnx模型加载失败的完整方案
  • 把RouterOS 7.x塞进VMware:不止是安装,更是打造你的第一个软路由实验平台