SQL加入Vs SQL子查询(性能)?

时间:2010-10-04 14:25:52

标签: sql performance sql-server-2008 subquery join

我想知道我是否有加入查询 -

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)

当我考虑性能时,哪两个查询会更快,而为什么

还有一段时间我应该更喜欢一个吗?

很抱歉,如果这太过琐碎并且之前被问过,但我很困惑。此外,如果你们可以建议我使用工具来测量两个查询的性能,那就太好了。非常感谢!

8 个答案:

答案 0 :(得分:42)

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

与ALL THINGS SQL一样,您的里程可能会有所不同。速度将在很大程度上取决于索引(你在两个ID列上都有索引吗?这将有很多帮助...)等等。

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

答案 1 :(得分:28)

嗯,我相信这是一个“老而金”的问题。答案是:“这取决于!”。 演出是如此微妙的主题,说:“永远不要使用子查询,永远加入”是太愚蠢了。 在以下链接中,您将找到一些我发现非常有用的基本最佳实践: 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.9秒。

我的查询最后是:

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,好。

答案 2 :(得分:9)

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

我不希望这些变得非常不同,在使用相关子查询时,使用连接而不是子查询可以获得真正的大量性能提升。

EXISTS通常比这两者中的任何一个更好,当你在谈论左连接时你想要的所有记录都不在左连接表中,那么NOT EXISTS通常是一个更好的选择。

答案 3 :(得分:4)

这两个查询可能在语义上不相同。如果一个员工在一个以上的部门工作(可能在我工作的企业;可以肯定,这意味着你的表没有完全规范化),那么第一个查询将返回重复行,而第二个查询则不会。要在这种情况下使查询等效,必须将DISTINCT关键字添加到SELECT子句中,这可能会对性能产生影响。

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

答案 4 :(得分:4)

效果取决于您正在执行的数据量......

如果它的数据少于20k左右。 JOIN效果更好。

如果数据更像是100k +,则IN工作得更好。

如果你不需要来自另一个表的数据,IN很好,但是最好去EXISTS。

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

答案 5 :(得分:3)

表现应该是一样的;在表上应用正确的索引和聚类更为重要(该主题上存在some good resources)。

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

答案 6 :(得分:1)

我知道这是一篇过时的文章,但是我认为这是一个非常重要的话题,尤其是在当今拥有1000万条以上记录并谈论数TB数据的情况下。

我还将强调以下几点。我的表([数据])中有大约4500万条记录,[猫]表中有大约300条记录。对于要讨论的所有查询,我都有广泛的索引编制。

考虑示例1:

UPDATE d set category = c.categoryname
FROM [data] d
JOIN [cats] c on c.id = d.catid

相对于示例2:

UPDATE d set category = (SELECT TOP(1) c.categoryname FROM [cats] c where c.id = d.catid)
FROM [data] d

示例1耗时约23分钟。示例2耗时约5分钟。

因此,我可以得出结论,这种情况下的子查询要快得多。当然,请记住,我正在使用I / o @ 1GB / sec(即字节而不是位)的M.2 SSD驱动器,因此索引的速度也非常快。因此,这可能也会影响您的速度

如果一次性清理数据,则最好让它运行并完成。我使用TOP(10000)来查看花费多长时间并乘以记录数,然后再执行大查询。

如果您正在优化生产数据库,我强烈建议您预处理数据,即使用触发器或作业代理来异步更新记录,以便实时访问检索静态数据。

答案 7 :(得分:0)

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

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