别再乱用 LEFT JOIN 了:EXISTS 的正确理解与实战对比

一、EXISTS 到底在做什么?

一句话概括:EXISTS 只判断“有没有匹配的行”,不关心匹配了几行,也不关心匹配行里有什么。

它的逻辑语义是:对左表的每一行,拿关联字段去子查询里找,只要能找到至少一条满足条件的记录,这行就保留;一条都找不到,就丢弃。

这决定了它两个关键特性:

  • 天然去重:右表匹配多条,也只算“有”,不会让左表行数膨胀。

  • 找到即停:匹配到第一条就停止扫描,不关心右表还有多少条。

二、示例场景

两张表:

订单表 orders

 
 
order_no tenant_id amount
A001 1 100
A002 1 200
A003 2 150

退款表 xq_order_refund

 
 
order_no tenant_id status
A001 1 0
A001 1 1
A002 1 1
A003 2 0

注意:A001 有 2 条退款记录(一条待处理、一条已处理),A002 只有已处理,A003 有待处理。

三、查“有待处理退款的订单”

写法一:EXISTS

sql
SELECT o.order_no, o.amount
FROM orders o
WHERE EXISTS (
    SELECT 1
    FROM xq_order_refund r
    WHERE r.order_no = o.order_no
      AND r.tenant_id = o.tenant_id
      AND r.status = 0
);

结果:

 
 
order_no amount
A001 100
A003 150

A001 只出现 1 次,因为 EXISTS 只判断“有没有”,不关心有几条。

写法二:LEFT JOIN

sql
SELECT DISTINCT o.order_no, o.amount
FROM orders o
LEFT JOIN xq_order_refund r
    ON r.order_no = o.order_no
   AND r.tenant_id = o.tenant_id
   AND r.status = 0
WHERE r.order_no IS NOT NULL;

结果和 EXISTS 一样,但必须加 DISTINCT。如果不加,A001 会因为退款表有 2 条记录而出现 2 次(一条匹配 status=0,一条匹配为 NULL)。

四、核心差异对比

 
 
维度 EXISTS LEFT JOIN
逻辑语义 判断“有没有匹配” 左表全保留,右表匹配就展开
匹配多条时 只算“有”,不膨胀 展开成多行,行数膨胀
是否需要 DISTINCT 不需要,天然去重 通常需要
能否取右表列 不能 可以
找到匹配后 立即停止 可能继续扫描
可读性 意图直接:找存在性 需要额外条件才等价

五、SELECT 1 怎么理解?

sql
EXISTS (SELECT 1 FROM ... WHERE ...)

SELECT 1 只是一个占位符。EXISTS 不关心 SELECT 后面写什么,写 1*id 都完全等价,性能没有任何区别。

写成 SELECT 1 是约定俗成的习惯,目的是告诉读代码的人:我不需要任何列,只判断存在性。

六、效率关键:索引

EXISTS 快不快,第一决定因素是索引,不是写法本身。

理想情况:在 xq_order_refund 上建联合索引

sql
CREATE INDEX idx_refund_order_tenant_status
ON xq_order_refund (order_no, tenant_id, status);

对每行订单做一次索引精确查找,找到即停,复杂度接近 O(N × logM),效率很高。

糟糕情况:没有索引,每行订单都全表扫描退款表,复杂度退化成 O(N × M),数据量大时会非常慢。

七、什么时候该用 EXISTS?

 
 
场景 推荐写法
只筛“有匹配”的订单,不需要退款表列 EXISTS
只筛“无匹配”的订单 NOT EXISTS
需要退款表的具体列(金额、时间等) LEFT JOIN
要保留所有订单,并标记是否有退款 LEFT JOIN + 去重子查询

八、总结

  • EXISTS 的核心是存在性判断,天然去重、找到即停。

  • 它和 LEFT JOIN 不等价:LEFT JOIN 会膨胀行数,EXISTS 不会。

  • 只判断“有没有”时,EXISTS 比 LEFT JOIN 更自然、通常也更高效。

  • 索引是前提:没有索引,换任何写法都救不了。

  • 写 EXISTS 时,子查询的 WHERE 条件必须和外表关联,否则结果会全错。

posted @ 2026-09-20 10:46  若-飞  阅读(4)  评论(0)    收藏  举报