JOIN 查询优化
面试官问:"JOIN 查询怎么优化?"
小张说:"给关联字段加索引。"
面试官追问:"JOIN 的执行过程是怎样的?"
小张说:"...先查左表再查右表?"
面试官继续追问:"那驱动表和被驱动表有什么区别?怎么选?"
小张开始支支吾吾。
JOIN 是 MySQL 面试中出现频率最高的复杂查询题之一。但 90% 的候选人只知道"加索引",说不清楚 JOIN 的执行过程、驱动表选择原理、以及 Nested Loop Join 和 Hash Join 的区别。
一、JOIN 执行原理 🔴
1.1 嵌套循环 JOIN(NLJ)
执行过程:
驱动表选择原则:
- 驱动表行数要少(减少被驱动表的访问次数)
- 被驱动表的关联字段要有索引
1.2 驱动表 vs 被驱动表
1.3 ❌ 错误示范
候选人原话:"LEFT JOIN 就是驱动表在左边,所以 orders 在前就是驱动表。"
问题诊断:LEFT JOIN 的关键字位置和驱动表选择无关。MySQL 优化器会自己判断哪个表做驱动表效率更高。
候选人原话 2:"JOIN 慢是因为数据量大,加索引就能解决。"
问题诊断:加索引可以加速被驱动表的查找,但如果驱动表行数太多(没有筛选条件),性能仍然很差。
【面试官心理】 这道题我会从 JOIN 执行过程切入。如果候选人能说清楚驱动表和被驱动表的关系,说明他对 JOIN 的底层原理有理解。
二、JOIN 缓冲区 🟡
2.1 Block Nested Loop Join(BNLJ)
当被驱动表没有索引时,MySQL 使用 BNLJ 算法:
执行过程:
2.2 JOIN Buffer 的配置
⚠️
BNLJ 算法在被驱动表没有索引时性能很差,因为需要全表扫描被驱动表多次。驱动表有多大,就需要扫描被驱动表多少次。
三、JOIN 优化策略 🟡
3.1 充分利用索引
3.2 控制驱动表行数
3.3 小表驱动大表
3.4 避免 SELECT *
四、Hash Join 🟢
4.1 Hash Join 的原理
MySQL 8.0+ 支持 Hash Join:
执行过程:
4.2 Hash Join 的限制
- MySQL 8.0+ 才支持
- 被驱动表需要有等值 JOIN 条件
- 大表 JOIN 大表时,需要足够大的
join_buffer_size
【面试官心理】 Hash Join 是 MySQL 8.0 的新特性。知道 Hash Join 和 NLJ 的适用场景差异的候选人,说明他对 MySQL 的演进有关注。