SQL - NOT IN内部的查询需要比完整查询更长的时间吗?

时间:2011-01-05 13:20:25

标签: sql oracle

我在SQL查询中使用NOT IN。

例如:

select columnA 
from table1
where columnA not in (
select columnB
from table2)

查询的这一部分怎么可能

select columnB
from table2

需要30秒才能完成,但上面的整个查询需要0.1秒才能完成? 整个查询不应该需要30秒+?

BTW,两个查询都返回有效结果。

谢谢!

评论回答

  

是因为第二个查询没有   实际完成但只有   返回第一个'x'行(out   一张非常大的桌子?)

不,查询在30秒后完成,而不是返回多行(例如50)。

  

但@Aleksandar想知道为什么   质疑表现的问题   杀手是如此之快。

我的观点正是

  

选择不同多长时间   table2中的columnB执行?

实际上,原始查询是“select distinct ...

6 个答案:

答案 0 :(得分:4)

这是因为查询优化器将查询转换为看起来完全不同的内容。实际查询应该与查询产生的查询相同:

select columnA 
from table1
left join table2 on ColumnA = ColumnB
where ColumnB is null

如果数据库可以使用索引来连接表,也许它不必查询整个table2,甚至不需要触摸表本身。

答案 1 :(得分:4)

您似乎认为主要查询意味着以下步骤:

(1)  Run the subquery
(2)  Check each row in table1 against the result set from the subquery.

因此,您认为分别运行子查询必须花费的时间少于运行整个查询。

但SQL不是一种过程语言,查询的结构并不一定意味着执行查询将遵循的步骤。

当Guffa回答时,优化器会提出(它认为是)执行每个查询的最佳计划。通过查看查询,这些执行计划并不总是显而易见的,在某些情况下确实可能非常违反直觉。

我认为在这种情况下,最有可能的是,优化器提出了一种更快的方法来检查table2中是否存在值,而不是简单地一次查询所有table2。这可能是Guffa所展示的转变(虽然这仍然没有告诉你使用的确切执行计划)。

我猜测table1的行数比table2少得多,而且table2.columnB上存在一个索引。所以它要做的就是从table1中获取行,然后探测每个值的索引以检查是否存在。但这只是一种可能性。

此外,正如Michael Buen指出的那样,返回的结果集大小的差异也会影响您的感知表现。我的直觉是,这是执行计划差异的次要因素,但它可能很重要。

答案 2 :(得分:2)

一个戏剧性的比较,让我们说这个......

select columnB
from table2

......有十亿行(30秒),许多数据通过电线传送给用户。

这就是......

select columnA 
from table1

...只有一行。

如果你不打算显示table2的数据,那么RDBMS不会把table2的数据从服务器拉到客户端。因此,在进行数据存在测试时不会涉及很多网络带宽或I / O,这一切都发生在服务器上,从服务器到客户端的唯一事情就是只有一行table1。

select columnA 
from table1
where columnA not in (
select columnB
from table2)

如果你的columnA和columnB碰巧有一个索引

,事情会特别快

使数据库操作变慢的因素有两个:第一个是从服务器向客户端提取过多数据,第二个是在相关字段上没有索引时

答案 3 :(得分:0)

当它可以使用索引时,返回的结果数量很少。有可能。返回结果可能会导致执行时间。

答案 4 :(得分:0)

进入,请确保您了解NOT In and NOT EXISTS之间的区别。

如果“columnA”为NULL,则不会通过您正在查看的NOT IN解决方案返回,但已经提供的LEFT反连接示例将表现为NOT EXISTS。

另外,确保TOAD / SQL Developer不只是“显示他们喜欢做的前50名”(从table1执行select count(*)以查看50是否确实是查询结果。)

对查询执行EXPLAIN PLAN并查看它是否突出显示任何看起来很恶劣的内容 - 检查索引并查看列是否允许NULLS - 缺少索引可能是罪魁祸首但是来自NULLS的全表扫描可能是造成噩梦)。

答案 5 :(得分:-1)

不是性能杀手。

在某些SQL引擎上首先将in(...)转换为临时表,重新运行查询,对临时表中的数据执行NOT。

如果可以,您应该只使用IN!