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

推荐订阅源

J
Java Code Geeks
GbyAI
GbyAI
阮一峰的网络日志
阮一峰的网络日志
Cloudbric
Cloudbric
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
宝玉的分享
宝玉的分享
I
Intezer
Simon Willison's Weblog
Simon Willison's Weblog
博客园_首页
The Cloudflare Blog
C
Cisco Blogs
AWS News Blog
AWS News Blog
IT之家
IT之家
Cyberwarzone
Cyberwarzone
罗磊的独立博客
美团技术团队
V
V2EX
Project Zero
Project Zero
A
Arctic Wolf
C
Cyber Attacks, Cyber Crime and Cyber Security
大猫的无限游戏
大猫的无限游戏
博客园 - 叶小钗
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 聂微东
有赞技术团队
有赞技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
雷峰网
雷峰网
S
Schneier on Security
P
Privacy International News Feed
V
Visual Studio Blog
量子位
T
Tor Project blog
S
Securelist
腾讯CDC
A
About on SuperTechFans
T
Threat Research - Cisco Blogs
G
GRAHAM CLULEY
B
Blog RSS Feed
D
DataBreaches.Net
博客园 - 三生石上(FineUI控件)
B
Blog
NISL@THU
NISL@THU
L
Lohrmann on Cybersecurity
V
Vulnerabilities – Threatpost
人人都是产品经理
人人都是产品经理
博客园 - 【当耐特】
L
LINUX DO - 热门话题
Recorded Future
Recorded Future

博客园 - 郭慕荣

彻底搞懂 Codex Skill 与插件:区别、试用、核心作用、项目落地全指南(程序员实战向) Codex Skill 和插件到底有什么区别?程序员如何在项目中落地使用 claudecode 配置防止配置文件泄露总结 Claude code分析外部文件总结 Claude code三种模式详解 hasCompletedOnboarding详解 Claudecode 有哪些常用的命令 claude.md文件详解 claude code 的setting文件详解 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 时,左表(左侧的表)的选择不仅影响结果集的完整性,还直接决定了查询性能。核心原则是:在满足业务逻辑的前提下,优先让小表作为左表,大表作为右表。但需注意,这一结论的前提是 “业务逻辑允许”—— 因为 LEFT JOIN 的核心是 “保留左表的所有记录,右表匹配不到则补 NULL”,左表的选择首先必须符合业务对结果集的要求(即需要完整保留哪些数据)。

LEFT JOIN 的执行效率与左表(驱动表)的大小、右表(被驱动表)的索引 / 大小密切相关,具体原因如下:

LEFT JOIN 的执行逻辑是:先遍历左表的所有行,再逐行到右表中匹配符合条件的记录。因此,左表的行数直接决定了 “需要执行多少次匹配操作”。

  • 若左表是小表(如 10 万行),则只需执行 10 万次匹配;
  • 若左表是大表(如 1 亿行),则需执行 1 亿次匹配,即使每次匹配效率很高,总耗时也会显著增加。

示例:假设左表 A 有 100 万行,右表 B 有 1 亿行,LEFT JOIN A ON B 需执行 100 万次匹配;若反过来 LEFT JOIN B ON A,则需执行 1 亿次匹配,后者的基础匹配次数是前者的 100 倍,性能差距悬殊。

右表的匹配效率取决于是否有合适的索引。大表通常会为连接字段(ON 后的条件字段)建立索引(否则全表扫描成本极高),而小表即使没有索引,全表扫描的成本也很低(因为数据量小)。

  • 若右表是大表且有索引:每次匹配可通过索引快速定位(如 B+ 树索引,单次查询时间复杂度 O (logN)),即使左表是小表,整体效率也很高;
  • 若右表是小表:即使没有索引,全表扫描(O (N))的成本也可接受(比如小表只有 1 万行,全表扫描 1 万次对数据库压力很小)。

反例:若左表是大表,右表是小表且无索引,此时左表的每一行都需要对右表做全表扫描,总耗时 = 大表行数 × 小表行数,性能会急剧下降(例如 1 亿 × 1 万 = 10 万亿次操作,完全不可接受)。

LEFT JOIN 的结果集行数 至少等于左表行数(右表匹配不到时补 NULL)。

  • 若左表是小表:结果集行数较少(如 10 万行),内存 / 磁盘存储压力小,后续处理(如排序、聚合)效率高;
  • 若左表是大表:结果集行数至少是大表行数(如 1 亿行),可能导致内存溢出(OOM)或磁盘临时文件暴涨,拖慢整个查询。

LEFT JOIN 的左表选择不能仅看性能,必须优先满足业务需求。例如:

  • 需查询 “所有用户的订单记录(包括没有订单的用户)”,此时 用户表 必须作为左表(即使 用户表 是大表,订单表 是小表);
  • 需查询 “所有商品的销售数据(包括未销售的商品)”,商品表 必须作为左表(无论大小)。

这种情况下,只能接受大表作为左表,但可通过以下方式优化性能:

  1. 给右表的连接字段建立索引(如 订单表.user_id),减少匹配耗时;
  2. 对左表进行过滤(如 WHERE 左表.日期 > '2023-01-01'),减少左表的实际行数;
  3. 避免在 LEFT JOIN 后使用 SELECT *,只查询必要字段,减少数据传输和存储成本。

部分数据库(如 PostgreSQL、Oracle)的优化器会对 JOIN 进行 “重排序”,但 LEFT JOIN 因语义限制(必须保留左表所有行),优化器无法交换左右表顺序。例如:

  • A LEFT JOIN B 中,优化器必须以 A 为驱动表,无法自动将 B 作为驱动表(即使 B 更小)。

而 MySQL 的优化器对 LEFT JOIN 的重排序限制更严格,几乎完全遵循用户指定的顺序。因此,用户必须主动选择更优的左表,不能依赖优化器自动调整。

  1. 业务优先:左表必须是 “需要完整保留所有记录” 的表(如 “用户表”“商品表”),这是 LEFT JOIN 的语义决定的;
  2. 性能优化:在满足业务的前提下,优先选择小表作为左表,大表作为右表,理由是:
    • 减少驱动表的行数,降低匹配次数;
    • 大表作为右表时,更易通过索引优化匹配效率;
    • 控制结果集大小,减少资源消耗。

一句话结论:先看业务需要保留哪个表的全部数据,再在这个前提下,选小的那个表做左表。