为什么MySQL关联查询要“小表驱动大表”?深入解析与模拟面试复盘


场景模拟:一场技术面试的攻防战

面试官:你在简历里提到优化过大量SQL查询,那你说说为什么MySQL做关联查询时建议用小表驱动大表?

候选人:因为用小表作为驱动表可以减少外层循环的次数,比如用INNER JOIN时,外层表行数越少,内层表扫描次数就越少,性能更好。


面试官(追问):那什么是"驱动表"?MySQL是如何决定哪个表作为驱动表的?

候选人:驱动表是执行计划中首先被访问的表,决定了连接顺序。MySQL优化器会根据统计信息(如索引、行数、数据分布)自动选择。但我们可以用STRAIGHT_JOIN强制指定驱动表。


面试官(深入):假设两个表都没有索引,为什么这时候"小表驱动大表"的性能差异会更明显?

候选人:如果被驱动表无索引,内层循环每次都要全表扫描。假设驱动表有N行,被驱动表有M行: • 小表驱动(N=100, M=1万):总扫描次数 = 100次全表扫描(1万行)→ 100万行

• 大表驱动(N=1万, M=100):总扫描次数 = 1万次全表扫描(100行)→ 100万行

虽然总行数相同,但前者需要更多磁盘I/O(大表数据分散),且可能触发缓存淘汰。


面试官(陷阱题):那如果被驱动表有索引,小表驱动还有必要吗?

候选人:此时性能差异可能缩小,但仍有优化空间。例如: • 小表驱动时,内层走索引查询,每次查找是O(log M)复杂度。

• 大表驱动时,内层虽然也走索引,但外层循环次数更多,CPU开销可能更高。

此外,驱动表数据量小,更容易放入join_buffer(若使用Block Nested-Loop Join算法)。


面试官(底层原理):能解释下Block Nested-Loop Join(BNL)和Index Nested-Loop Join(INL)的区别吗?

候选人: • INL:被驱动表有索引时,内层循环直接通过索引定位数据,时间复杂度O(N log M)

• BNL:无可用索引时,将驱动表加载到join_buffer,批量匹配被驱动表,时间复杂度O(N * M)。此时用小表驱动可降低内存占用,减少磁盘扫描次数。


面试官(实战场景):如何判断一条关联查询是否使用了最优驱动表?

候选人:通过EXPLAIN查看执行计划: • 第一行出现的表即为驱动表。

• 关注type字段:ref/range表示索引有效,ALL表示全表扫描。

• 检查rows预估行数,对比实际数据量判断统计信息是否准确。


核心结论

  1. 性能本质:减少外层循环次数 + 利用索引降低内层循环代价。

  2. 优化器局限:统计信息过期、复杂过滤条件可能导致优化器误判。

  3. 判断标准: • 当被驱动表无索引 → 严格遵循"小表驱动大表"。

    • 当被驱动表有索引 → 优先保证内层循环走索引,驱动表选择次之。

  4. 终极方案:通过EXPLAIN验证执行计划,必要时用FORCE INDEXSTRAIGHT_JOIN干预。


面试官:不错,今天先聊到这儿。回去等通知吧。(暗中点头)


附录:经典优化公式

总查询代价 ≈ 驱动表查询成本 + 驱动表行数 × 单次被驱动表查询成本

通过降低驱动表的行数或降低被驱动表的单次查询成本(如加索引),可显著提升性能。


相关推荐
rannn_11116 分钟前
【苍穹外卖|Day4】套餐页面开发(新增套餐、分页查询、删除套餐、修改套餐、起售停售)
java·spring boot·后端·学习
短剑重铸之日26 分钟前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
Dragon Wu1 小时前
Spring Security Oauth2.1 授权码模式实现前后端分离的方案
java·spring boot·后端·spring cloud·springboot·springcloud
一个有梦有戏的人2 小时前
Python3基础:进阶基础,筑牢编程底层能力
后端·python
爬山算法2 小时前
Hibernate(88)如何在负载测试中使用Hibernate?
java·后端·hibernate
独断万古他化2 小时前
【Spring 原理】Bean 的作用域与生命周期
java·后端·spring
我爱加班、、2 小时前
Websocket能携带token过去后端吗
前端·后端·websocket
一 乐3 小时前
校园二手交易|基于springboot + vue校园二手交易系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端
80530单词突击赢3 小时前
SpringBoot整合SpringMVC全解析
java·spring boot·后端
hdsoft_huge3 小时前
1panel面板中部署SpringBoot和Vue前后端分离系统 【图文教程】
vue.js·spring boot·后端