2010-10-04 100 views
72

我想知道如果我有一个加入查询是这样的 -SQL加入Vs SQL子查询(性能)?

Select E.Id,E.Name from Employee E join Dept D on E.DeptId=D.Id 

子查询这样的事情 -

Select E.Id,E.Name from Employee Where DeptId in (Select Id from Dept) 

当我考虑性能其中两个查询会更快,为什么

也有一段时间,我应该更喜欢一个在另一个?

对不起,如果这太微不足道,以前问过,但我很困惑。此外,如果你们可以建议我工具我会用它来衡量两个查询的性能。非常感谢!

+3

另请参阅http://stackoverflow.com/questions/2577174/sql-join-vs-subquery – Lucero 2010-10-04 14:44:21

+3

@Lucero,这个问题被标记为sql-server-2008,其中你提到的帖子标记为MySql。你可以推断答案是一样的。性能优化在两个RDBMS上完成的方式不同。 – 2012-04-25 15:35:54

回答

36

我希望先查询要快,主要是因为你有一个等价和显式连接。根据我的经验,IN是一个非常慢的运算符,因为SQL通常将其评估为由“OR”(WHERE x=Y OR x=Z OR...)分隔的一系列WHERE子句。

与所有这些SQL虽然,你的里程可能会有所不同。速度将取决于很多索引(你是否在两个ID列上都有索引?这将有助于很多...)等等。

以更快的速度告诉100%确定性的唯一真正方法是开启性能跟踪(IO统计特别有用)并同时运行它们。确保在运行之间清除缓存!

+9

我对此回答有严重疑问,因为绝大多数DBMS,绝对是SQL Server 2008及更高版本,都将单个ID子查询(不相关,意思是:不引用多个外部查询列)转换为相对较快的半联接。此外,正如前面在另一个答案中指出的那样,第一个真正的连接将返回一行,以便在每个事件中发现匹配的ID - 这对于唯一ID没有任何影响,但会在其他地方给您带来大量重复。用DISTINCT或GROUP BY对它们进行排序将是另一个严重的性能负载。检查SQL Server Management Studio中的执行计划! – 2013-12-27 09:32:51

+1

作为OR等价物的IN子句适用于参数/值列表,但不适用于子查询,它们通常被视为联接。 – 2013-12-27 09:55:01

2

表现应该是一样的;在表格上应用正确的索引和集群更重要(有关该主题的some good resources)。

(编辑,以反映更新后的问题)

+0

我更新了我的问题以更改查询很少...感谢您的回复。 – Vishal 2010-10-04 14:33:28

0

您可以使用解释计划来获得客观答案。

对于您的问题,an Exists filter可能会执行得最快。

+2

“一个存在过滤器可能执行速度最快” - 可能不是,我认为,虽然明确的答案需要测试实际数据。如果有多个行具有相同的查找值,则存在过滤器可能会更快 - 因此,如果查询检查其他员工是否从同一部门录制过,则存在过滤器可能运行得更快,但在查看部门时可能不会表。 – 2010-10-04 15:05:20

+0

它会在最后一种情况下运行得慢吗? – Snekse 2010-10-04 17:08:00

+0

这取决于优化器 - 在某些情况下,它可能,但通常我会期望非常相似的性能。 – 2010-10-05 12:47:10

9

开始查看执行计划以查看SQl Server如何解释它们的差异。您还可以使用Profiler实际运行多次查询并获得不同的结果。

我不希望这是如此可怕的不同,在那里你可以得到使用中获得真正的,大的性能提升联接,而不是子查询是当您使用相关子查询。

EXISTS往往比这两种的,当你在谈论离开联接要不是在左侧的所有记录的连接表更好,那么NOT EXISTS往往是一个更好的选择。

3

这两个查询可能不是语义等价的。如果一个员工为多个部门工作(可能在我工作的企业中;诚然,这意味着您的表没有完全标准化),那么第一个查询将返回重复的行,而第二个查询则不会。为了在这种情况下使查询等效,DISTINCT关键字必须添加到SELECT子句中,这可能会影响性能。

请注意,有一个设计经验法则规定一个表应该为实体/类或实体/类之间的关系建模,但不能同时建模这两个实体/类。因此,我建议您创建第三个表格,如OrgChart,来模拟员工和部门之间的关系。

4

性能是根据正在执行的数据量...

如果是20K左右的数据量。 JOIN工作得更好。

如果数据更像100k +,那么IN效果更好。

如果你不需要来自另一个表的数据,那么IN是好的,但是对于EXISTS来说最好还是更好。

我测试的所有这些标准和表都有适当的索引。

22

嗯,我相信这是一个“旧但金”的问题。答案是:“这取决于!”。 表演是一个非常微妙的主题,所以说:“永远不要使用子查询,总是加入”太愚蠢了。 在下面的链接,你会发现,我已经发现了一些基本的最佳实践是非常有帮助的: Here 1 Here 2 Here 3

我有50000元的表格,结果我一直在寻找为739元。

我在第一个查询是这样的:

SELECT p.id, 
    p.fixedId, 
    p.azienda_id, 
    p.categoria_id, 
    p.linea, 
    p.tipo, 
    p.nome 
FROM prodotto p 
WHERE p.azienda_id = 2699 AND p.anno = (
    SELECT MAX(p2.anno) 
    FROM prodotto p2 
    WHERE p2.fixedId = p.fixedId 
) 

,并花了7.9s执行。

我最后的查询是这样的:

SELECT p.id, 
    p.fixedId, 
    p.azienda_id, 
    p.categoria_id, 
    p.linea, 
    p.tipo, 
    p.nome 
FROM prodotto p 
WHERE p.azienda_id = 2699 AND (p.fixedId, p.anno) IN 
(
    SELECT p2.fixedId, MAX(p2.anno) 
    FROM prodotto p2 
    WHERE p.azienda_id = p2.azienda_id 
    GROUP BY p2.fixedId 
) 

,并花了0.0256s

SQL好,好。

+0

有趣,你能解释一下如何添加GROUP BY修复它吗? – cozos 2017-11-08 23:27:39

-1

最终查询在相关子查询中包含azienda_id,但您的初始查询不包括核心子查询中的azienda_id。所以比较是不一样的。

+0

这应该是对linuxatico的答案的评论。 – jojonas 2016-09-08 10:47:41

-1

我已经通过比较'使用客户统计'的数量测试了HLGEM的理论,结果表明不存在比搜索左表中所有记录时的左连接快。

SQL的美妙之处在于它的写作方式很多,性能并不完全取决于连接或子查询,而是您正在寻找的结果集。