惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 郭慕荣

Docker部署zookeeper总结 Mac中git ssh的配置(GitLab) Java 类加载机制 面试题(一) 如何监控和调优JVM性能? jvm常用的参数有哪些? 怎么配置? hashmap 和currenthashmap 的原理?详解一下 aop在项目中使用的场景?怎么使用? Java dubbo spring springboot中的spi机制 spring中常见的两种代理模式 Redis的zset 面试汇总 drools 规则引擎在线化配置 - 郭慕荣 springcloud中常用的注解详解 springcloud中网关gateway总结 spring是怎么解决循环依赖的? MySQL 死锁 怎么处理? 在写left join的时候 是大表在左侧 还是小表在左侧(二) nacos客户端(接口调用者)如何感知被调用服务下线? (二) nacos客户端(接口调用者)如何感知被调用服务下线?(一) 在MySQL中 redolog undolog binlog 写入的场景,顺序 - 郭慕荣
在写left join的时候 是大表在左侧 还是小表在左侧(一)
郭慕荣 · 2025-10-21 · via 博客园 - 郭慕荣

好——这个问题既是面试高频点,也是写生产 SQL 时必须搞清楚的性能细节。下面把概念 + 引擎实现 + 左连接(LEFT JOIN)语义影响 + 实际优化建议与排查清单都讲清楚,你能直接在面试里条理化回答,也能在工程中落地排查与优化。

结论先说一句话

  • 性能上通常希望“驱动(build/probe)侧是小表”:无论是嵌套循环(Nested-Loop)还是哈希(Hash)连接,数据库都倾向于对小表做构建或做外层遍历以减少工作量。

  • 但对 LEFT JOIN(外连接)要小心:外连接的语义限制了优化器随意重排表顺序,因此如果你想让小表做“驱动”,需要注意写法或使用 hint/STR AIGHT_JOIN 强制。Database Administrators Stack Exchange+1

1) 先看:数据库常见的连接算法(会影响“谁做”)

  • 索引嵌套循环(Index Nested-Loop):外层逐行扫描,内层用索引按键快速查找。适合外层较小或内层有合适索引的场景。MySQL 传统上大量使用这种方式。Medium

  • 哈希连接(Hash Join):先对“较小的一方”构建哈希表(build),再扫描“较大的一方”并 probe 哈希表匹配。MySQL 从 8.0.18 起支持 hash join(主要用于等值内连接)。因此哈希连接更要求把小表作为 build side。MySQL开发者区+1

  • 排序合并(Sort-Merge Join):对两边排序后线性合并(MySQL 对此支持受限,具体实现/可用性与版本有关)。Medium

结论:不论哪种算法,把更小、选择性更高、或能建立索引的表放在“build/外层”通常更高效(少 I/O、少 probe/比较)。

2) LEFT JOIN 的语义与优化器重排问题(面试必问点)

  • LEFT JOIN a LEFT JOIN b 的语义:左表的每一行必须保留(即使右表无匹配,用 NULL 填充)。这语义限制了优化器能做的重排(不能随意把右表当做外层表来改变逻辑结果)。MySQL 优化器在重写/重排连接时要保证外连接的语义不被破坏,因此在某些情况下无法或不会把右表提前为驱动表MySQL开发者区+1

  • 实战结果:对 LEFT JOIN,想让小表“先被处理”需要注意

    • 如果你用的是内连接(INNER JOIN),优化器可自由重排,通常会选最优驱动顺序(常把小表做 build)。

    • LEFT JOIN 有语义约束,优化器可能必须先读取左表,然后为每行查右表(外层为左表),这在左表非常大时可能代价高(大量探针)。因此如果左表很大而你希望效率更高,需考虑改写或调整索引/提示。Stack Overflow+1

3) 实际建议(工程化可执行的规则)

下面按“你能马上应用”的清单写,便于面试与工程落地。

A. 优先保证索引(最重要)

  • 无论 join 顺序,右表(被查找表)的 join 列必须有合适索引,这样即便外层是大表,内层也能快速通过索引定位匹配,避免全表扫描。

B. 让“更小的表作为 build/驱动”——如何做到

  • 如果是 INNER JOIN:数据库会倾向于最优驱动顺序(小表做 build)。只需确保统计信息和索引正确。

  • 如果是 LEFT JOIN,但语义上你可以把逻辑改成等价的 INNER JOIN(例如把过滤条件提早到 ON/WHERE,使行必然匹配),那就改为 INNER JOIN。否则:

    • 重写查询:用子查询先把小表聚合/筛出(derived table/临时表),对其建立索引或物化,再 join 大表。

    • 用 STRAIGHT_JOIN 强制顺序(MySQL):SELECT /*+ STRAIGHT_JOIN */ ...STRAIGHT_JOIN 关键字,让写表顺序成为驱动顺序(小心语义与正确性)。

    • 利用 optimizer hints(MySQL 8.0+)JOIN_ORDER() 等 hint(视版本)来影响重排。

C. 对于 MySQL 8+:若能用 Hash Join,效果更好

  • 在 MySQL 8.0.18+ 若走 hash join,查询会先对小表构建 hash,然后扫描大表 probe;这符合“小表先做 build”的规则。检查 EXPLAIN 看是否采用 hash join。MySQL开发者区

D. 避免产生过多临时结果与排序

  • 如果 JOIN 前没有先筛选,会乘法级别扩大中间行数(导致 temp table / disk spill)。尽量把过滤(WHERE 条件)尽早下推或先在 derived table 中做聚合/筛选,减少中间集大小。

E. 监控与调整参数(MySQL 特有)

  • 若查询使用大量全表扫描,MySQL 可能使用 join_buffer(用于没有索引时的块嵌套)。可查看 join_buffer_size,但更优是补索引或改写查询。

  • 对 HASH JOIN,注意内存和 hash 表大小(由服务器自动控制,但需要关注内存使用)。use-the-index-luke.com

4) 排查步骤(在生产中你应该怎么做)

  1. 先用 EXPLAINEXPLAIN ANALYZE(MySQL 8)查看执行计划(观察 join type、possible_keys、rows、Extra 是否用 Using where/Using index/Using temporary)。

  2. 看 optimizer 是否选择 nested-loop、hash join 或全表扫描。若是 nested-loop 且外层是大表且内层没有索引 → 性能问题的常见原因。Medium

  3. 若 LEFT JOIN 导致外层大表全表扫描且结果慢,考虑:加索引 / 将小表先聚合成临时小表 / 改写成 EXISTS(有时 EXISTS 更高效)或使用 STRAIGHT_JOIN 强行改变执行顺序测试效果(注意语义)。Database Administrators Stack Exchange+1

  4. 做对比测试(改写前后在测试库跑 explain / timing),不要盲目在生产直接改写。

5) 常见面试问答要点(简短可背)

  • 问:LEFT JOIN 时哪个表放左边更好?
    答:语义上左边是要保留的表;性能上你通常希望 小表作为 build / 驱动(这样 probe 次数少)。但 LEFT JOIN 的语义可能禁止优化器把右表先做驱动,因此如果左表很大需要改写查询或使用 hint/临时表来让小表先被处理。务必保证被 probe 的表有索引,并用 EXPLAIN 验证执行计划。Database Administrators Stack Exchange+1

  • 问:MySQL 支持哈希连接吗?会影响 join 顺序吗?
    答:从 MySQL 8.0.18 开始支持 Hash Join(主要用于等值内连接),Hash Join 会把小表做 build并对大表 probe;因此在能走 hash join 时,使小表为 build side 性能更优。MySQL开发者区+1

6) 小结 — 实战优先级

  1. 先看执行计划(EXPLAIN) —— 确认 join 算法、是否有索引、rows 估算。

  2. 保证 join 列有索引(特别是被查表的列)。

  3. 尽量让小表做 build/驱动:对于 INNER JOIN 由优化器处理;对于 LEFT JOIN,若左表很大且性能差,考虑改写(子查询/derived)或 hint/STRAIGHT_JOIN。

  4. 考虑 Hash Join(MySQL 8.0.18+):当可用时对大表/小表组合很有利(小表作 build)。

  5. 用实际测量(EXPLAIN ANALYZE / timing)来验证每一步,别凭直觉改造查询。