mysql LEFT JOIN像不像集合并集_mysql连接原理理解

来源:这里教程网 时间:2026-02-28 20:47:39 作者:

LEFT JOIN
不是集合并集,它是“左表全集 + 右表匹配子集”的组合,带
NULL
填充;而并集(
UNION
)是去重后的行合并,语义和结果都完全不同。


LEFT JOIN 的本质:左表驱动的保留式关联

它不是数学集合运算,而是基于驱动表逐行扫描、按条件查找匹配的执行过程。MySQL 内部用

Nested-Loop Join
(嵌套循环)实现:
– 左表每行作为基准,去右表找所有满足
ON
条件的行;
– 找到则拼接成结果行;
– 找不到就补
NULL
,但左表这行仍保留。

LEFT JOIN
结果行数 ≥ 左表行数(一对多时会膨胀)
右表无索引时,可能触发
Block Nested-Loop Join
,导致全表扫描右表多次,性能骤降
ON
条件只控制“如何匹配”,不负责过滤;
WHERE
才真正筛最终结果——这点极易误用
SELECT u.id, u.name, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.amount > 100;

⚠️ 这条语句实际等效于

INNER JOIN
:因为
WHERE
o.amount
过滤,会把
o.amount IS NULL
的行全干掉。想保留用户即使没大额订单,得写成:

SELECT u.id, u.name, o.amount
FROM users u
LEFT JOIN orders o ON u.id = o.user_id AND o.amount > 100;

为什么不能当成 UNION 理解?

UNION
是垂直拼接两组独立查询结果,要求列数、类型兼容,且自动去重;
LEFT JOIN
是水平扩展字段,行与行之间存在逻辑绑定关系(靠
ON
维系),且绝不自动去重。

UNION
:两表各查 10 行 → 最多返回 20 行(去重后可能更少)
LEFT JOIN
:左表 10 行 × 右表平均 2 行匹配 → 返回 20 行(无去重,结构拉宽)
字段来源不同:
UNION
字段必须同名/同序;
LEFT JOIN
可混用任意字段,甚至加计算列

连接原理落地:驱动表 + 索引决定性能生死线

MySQL 优化器默认选小表作驱动表,但

LEFT JOIN
强制左表为驱动表——所以左表数据量要可控,右表必须在
ON
字段上有索引,否则就是灾难。

检查执行计划:
EXPLAIN SELECT ... LEFT JOIN ...
,重点看
type
是否为
ref
range
Extra
是否含
Using index condition
Extra
出现
Using join buffer (Block Nested Loop)
,说明右表没走索引,正在暴力扫描
右表连接字段缺失索引?立刻加:
ALTER TABLE orders ADD INDEX idx_user_id (user_id);

最容易被忽略的坑:ON 和 WHERE 的语义鸿沟

这是线上慢查和空结果的头号元凶。记住口诀:

ON
定义“谁跟谁配对”;
WHERE
定义“最后留哪些行”。

把右表过滤条件写在
ON
里 → 保留左表全部,未匹配项右字段为
NULL
把右表过滤条件写在
WHERE
里 → 实际砍掉所有右表不满足的行,包括本该保留的左表记录
多表
LEFT JOIN
时,每个
ON
只作用于紧邻的右表,不跨表生效

复杂关联下,宁可拆成子查询或 CTE 显式控制逻辑,也不要靠直觉堆

LEFT JOIN
+
WHERE

相关推荐