SQL 外连接的执行过程解析

10次阅读

外连接中驱动表优先匹配,被驱动表需关联字段索引;ON决定匹配逻辑,WHERE过滤最终结果;NULL填充无法索引加速,哈希外连接仅在无索引全扫时可能提速。

SQL 外连接的执行过程解析

外连接执行时,驱动表和被驱动表怎么选

外连接的执行顺序不完全由 sql 写法决定,而取决于优化器对 JOIN 顺序的选择。左外连接(LEFT JOIN)中,左侧表默认为驱动表,右侧表为被驱动表;右外连接(RIGHT JOIN)则相反。但若开启 optimizer_switch='join_cache_level=2' 或存在合适索引,优化器可能重排顺序——此时 EXPLaiNtable 列顺序和 type 字段(如 ref vs ALL)才是真实执行路径的关键依据。

常见错误现象:明明写了 LEFT JOIN,却在 WHERE 子句里对右表字段加了非空条件(如 WHERE t2.status = 'active'),结果变成隐式内连接——因为过滤发生在连接后,NULL 行被直接剔除。

  • 驱动表应尽量小,或有高选择性索引,减少循环次数
  • 被驱动表必须在关联字段上有索引,否则触发全表扫描(type: ALL
  • STRAIGHT_JOIN 可强制按书写顺序执行,但需确认统计信息准确,否则反而更慢

ON 条件和 WHERE 条件在外连接中的作用差异

ON 是连接阶段的“匹配规则”,决定哪些行能组成临时结果;WHERE 是连接完成后的“最终过滤”,会筛掉已生成的整行(包括左表数据)。对左外连接来说,ON 中右表条件不满足时,右表字段补 NULL,左表行仍保留;而 WHERE 中对右表字段的限制会让这些 NULL 行消失。

示例:select * FROM orders o LEFT JOIN users u ON o.user_id = u.id AND u.status = 'active' —— 这里 u.status = 'active'ON 中,不影响 orders 行输出;若挪到 WHERE u.status = 'active',则所有无匹配活跃用户或用户为非活跃的订单都会被过滤掉。

  • ON 支持对任意表字段做条件,包括被驱动表的非索引字段(但性能差)
  • WHERE 中对被驱动表字段的等值条件,可能让优化器放弃外连接语义,转为内连接执行
  • 多表外连接链(如 A LEFT JOIN B LEFT JOIN C)中,ON 条件只作用于相邻两表,不能跨跳

NULL 值填充发生在哪一步,能否被索引利用

NULL 填充是外连接算法的最后一步:先完成驱动表与被驱动表的匹配(类似内连接逻辑),再将未匹配的驱动表行单独拎出,对其被驱动表字段补 NULL。这个过程发生在存储引擎返回数据之后、Server 层组装结果之前,因此无法被任何索引加速——索引只参与匹配阶段的查找,不参与补 NULL。

这意味着:即使被驱动表完全没数据,只要驱动表有 100 万行,外连接结果也至少有 100 万行,且每行都要构造一次 NULL 值。如果后续还有 GROUP BYORDER BY,代价会进一步放大。

  • 补 NULL 不触发磁盘 I/O,但增加 CPU 和内存开销(尤其大字段如 TEXT
  • 联合索引无法覆盖 “驱动表有值 + 被驱动表无匹配” 这一场景,所以别指望靠索引避免 NULL 行
  • EXPLAIN format=jsON 查看 filtered 字段,若被驱动表的 filtered 接近 0,说明大量行未匹配,补 NULL 开销已成瓶颈

mysql 8.0+ 的哈希外连接是否真能提速

MySQL 8.0.18 引入了哈希外连接(Hash Outer Join),但仅适用于被驱动表走全表扫描(type: ALLtype: index)且无合适索引的场景。它把驱动表建哈希表,再流式扫描被驱动表做探测。相比嵌套循环,它减少了随机 I/O,但内存占用更高,且不支持被驱动表使用索引查找(即不兼容 ref/eq_ref)。

是否启用由优化器自动判断,可通过 SET optimizer_switch='hash_join=on' 手动打开,但需注意:若驱动表太大导致哈希表溢出磁盘,性能反而暴跌;且哈希连接不支持 using 语法,只认 ON 显式条件。

  • 查看 EXPLAIN 输出中 Extra 是否含 Using where; Using join buffer (hash join)
  • 哈希外连接无法下推 WHERE 条件到被驱动表扫描前,所以过滤越晚,扫描越多
  • 小数据量(

外连接的真实开销往往不在连接本身,而在补 NULL 后的数据流转——比如后续排序、聚合、网络传输,这些环节对 NULL 的处理成本常被低估。

text=ZqhQzanResources