EXISTS 和 JOIN 之间检查记录是否存在的区别

Difference between EXISTS and JOIN to check existence of records

看下面的例子:

SELECT *
FROM customers
WHERE EXISTS
    (SELECT *
     FROM order_details
     WHERE customers.customer_id = order_details.customer_id)
;

检索相同结果集的两个表之间基于 inner join 的等效查询有哪些区别?

我关心的是 technical/performance 方面,而不是代码的 readability/mantainabilty。

EXISTS 在逻辑上的工作方式如下

for x in (select * from customers)
loop
      -- check if x.customer_id exists in order_details table.    
      ---if yes 
          --output the customer tables row
      -- else 
         --ignore 
end if;
end loop;

所以在存在查询中,计划通常会使用嵌套循环(虽然不是硬性规则)

JOIN 查询的逻辑等价物如下

for x in (select * from customers)
loop
  --for each row in customer 
  -- fetch records from order_details which match this condition
      select * from order_details where customer_id=x.customerid     
end loop;

使用 EXISTS 子句,您 select 存在至少一个 order_details 记录的所有客户。

SELECT * 
FROM customers c
WHERE EXISTS (SELECT * FROM order_details od WHERE od.customer_id = c.customer_id);

通过加入,您会再次 select 这些客户。但是,只要它们存在 order_detail,您就会 select 每个。 IE。你会有很多重复。

SELECT c.*
FROM customers c
JOIN order_details od ON c.customer_id = od.customer_id;

您可以使用 DISTINCT 从结果中删除重复项,以便再次获得每个客户一次:

SELECT DISTINCT c.*
FROM customers c
JOIN order_details od ON c.customer_id = od.customer_id;

但为什么生成了所有重复项却不得不再次删除它们?不要这样做。仅在您真正想要合并结果时才加入。

我认为比 EXISTS 子句更具可读性的另一个选项是 IN 子句。这将是我编写查询的方式:

SELECT * FROM customers WHERE customer_id IN (SELECT customer_id FROM order_details);

EXISTS()被称为"semi-join"。它开始 JOIN,但在找到第一个匹配项时停止。因此,EXISTS 将比任何等效的 JOIN.

更快

此外,EXISTS( SELECT * ... WHERE ... )并不真正关心*。它将使用任何最佳索引来发现匹配 WHERE 的行是否存在,然后它 returns 1 或 0(意思是 "true" 或 "false")。

当然,如果 LEFT JOIN 将要 return 0 或 1 行,不会更多,则性能差异不大。除了 LEFT JOIN 将 return 来自 table 的值。