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

时间:2018-12-12 10:15:59

标签: mysql sql performance join exists

看下面的例子:

merge into MAGIC_TABLE magic
using (
    with UNMAGIC_TABLE as (
        select titi, tata from MAGIC_TABLE
        and tata='magic2'
    )
    SELECT titi, tata from UNMAGIC_TABLE 
) really_unmagic
on 
(
  magic.titi = really_unmagic.titi
  magic.tata = really_unmagic.tata
  and magic.tata='magic1'
) 
when not matched then insert (titi, tata) 
values 
(really_unmagic.titi, 'magic1');

在两个检索相同结果集的表之间,基于等效SELECT * FROM customers WHERE EXISTS (SELECT * FROM order_details WHERE customers.customer_id = order_details.customer_id) ; 的查询有哪些区别?

我关注的是技术/性能方面,而不是代码的可读性/可维护性。

3 个答案:

答案 0 :(得分:2)

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

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

通过加入,您将再次选择那些客户。但是,只要有一个order_detail即可选择它们。即你会有很多重复。

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);

答案 1 :(得分:1)

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;

答案 2 :(得分:1)

EXISTS()被称为“半连接”。它从JOIN开始,但是在找到第一个匹配项时停止。因此,EXISTS比任何等效的JOIN都要快。

此外,EXISTS( SELECT * ... WHERE ... )并不真正关心*。它将使用最佳索引来发现与WHERE匹配的行的存在与否,然后返回1或0(表示“ true”或“ false”)。

当然,如果LEFT JOIN将返回0或1行,再也不会返回,那么性能差别就不会太大。除了LEFT JOIN将返回表中的值。