SQL:IN vs EXISTS

时间:2014-07-07 09:13:47

标签: sql oracle10g exists

我读过,通常你应该在子查询的结果很大时使用EXISTS,而在子查询结果很小时使用IN

但在我看来,如果必须为每一行重新评估子查询,或者如果可以为整个查询评估一次子查询,那么它也是相关的。

考虑以下两个等效查询的示例:

SELECT * FROM t1
WHERE attr IN
(SELECT attr FROM t2
WHERE attr2 = ?);

SELECT * FROM t1
WHERE EXISTS
(SELECT * FROM t2
WHERE t1.attr = t2.attr
AND attr2 = ?);

前一个子查询可以针对整个查询进行一次评估,后者必须针对每一行进行评估。

假设子查询的结果非常大。这是写这个的最好方法吗?

1 个答案:

答案 0 :(得分:1)

这是一个很好的问题。特别是在Oracle中,您可以将每个EXISTS子句转换为IN子句,反之亦然,因为Oracle的IN子句可以处理元组(where (abc) in (select x,y,z from ...),而其他大多数dbms都不能。

你的理由很好。是的,使用IN子句,您建议一次加载所有子查询的数据,而不是在循环中查找记录。然而,这只是部分正确,因为:

  • 似乎只选择了一次所有子查询数据,外部查询必须遍历每个记录的结果数组。这可能很慢,因为它只是一个数组。如果Oracle在表中查找数据而不是通常有索引来帮助它,那么具有重复表查找的嵌套循环最终会更快。
  • Oracle的优化器重写了查询。因此,对于这两个陈述,它可以达到相同的执行计划,甚至可以达到非常意外的计划。你永远不知道; - )
  • Oracle可能会决定不循环。它可能决定使用散列连接,它的工作方式完全不同,通常非常有效。

说到这里,Oracle的优化器应该注意到这两个语句实际上是完全相同的,应该生成相同的执行计划。但是经验表明优化器有时候并没有注意到,并且通常优化器出于某种原因使用EXISTS子句做得更好。 (与MySQL不同,但是,在Oracle中,EXISTS似乎优于IN。)

关于你的问题"假设子查询的结果非常大。哪个是写这个的最好方法?",IN子句不可能比EXISTS子句更快。

我经常更喜欢IN子句的简单性,并且大多数人觉得它更具可读性。但是在性能方面,有时最好使用EXISTS(甚至是外连接)。