SQL 连接与 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)

当我考虑 表演时,这两个查询中哪一个更快,哪一个更快?

还有,有没有时候我应该选择其中一个而不是另一个?

对不起,如果这是过于琐碎和问之前,但我对此感到困惑。另外,如果你们能够建议我使用 工具来度量两个查询的性能,那就太好了。非常感谢!

188528 次浏览

性能应该是相同的; 在表上应用正确的索引和集群更为重要(关于这个主题存在 一些好的资源)。

(为反映最新问题而编辑)

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

但是,和所有的事情 SQL 一样,你的情况可能会有所不同。速度在很大程度上取决于索引(是否在两个 ID 列上都有索引?这将有很大帮助...)。

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

你可以使用一个解释计划来得到一个客观的答案。

对于您的问题,存在过滤器可能是执行速度最快的。

开始查看执行计划,以了解 SQLServer 将如何解释它们之间的差异。您还可以使用 Profiler 实际多次运行查询并获得差异。

我不会期望它们有如此可怕的不同,当您使用相关的子查询时,您可以通过使用连接而不是子查询获得真正的、大量的性能提升。

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

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

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

性能是基于您正在执行的数据量..。

如果数据少于20k,JOIN 工作得更好。

如果数据大约是100k + ,那么 IN 工作得更好。

如果您不需要来自其他表的数据,IN 是好的,但是最好使用 EXISTS。

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

好吧,我相信这是一个“古老但黄金”的问题。答案是: “这取决于!”。 表现是一个如此微妙的主题,如果说: “永远不要使用子查询,始终使用 join”,那就太愚蠢了。 在下面的链接中,你会发现一些基本的最佳实践,我发现它们非常有帮助:

我有一个包含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.0256秒

很好的 SQL,很好。

我知道这是一篇老文章,但我认为这是一个非常重要的话题,特别是现在,我们有10M 以上的记录,谈论的是 TB 级的数据。

我还将加入以下观察结果。我的表([数据])中有大约45M 条记录,我的[ cat ]表中有大约300条记录。我有大量的索引为所有的查询,我要谈论。

例子一:

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分钟。

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

如果这是一次性的数据清理,最好还是让它运行并完成。我使用 TOP (10000) ,看看需要多长时间,然后乘以记录的数量,然后执行大查询。

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