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

Vis*_*hal 100 sql performance join subquery sql-server-2008

我想知道我是否有这样的连接查询 -

Select E.Id,E.Name from Employee E join Dept D on E.DeptId=D.Id
Run Code Online (Sandbox Code Playgroud)

和这样的子查询 -

Select E.Id,E.Name from Employee Where DeptId in (Select Id from Dept)
Run Code Online (Sandbox Code Playgroud)

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

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

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

JNK*_*JNK 45

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

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

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

  • 我对这个答案有严重怀疑,因为大多数DBMS,肯定是SQL Server 2008及更高版本,将单个ID子查询(不相关,意思是:不引用多个外部查询列)转换为相对快速的半连接.此外,正如之前在另一个答案中所指出的,第一个真正的连接将为Dept中匹配ID的每次出现返回一行 - 这对于唯一ID没有任何区别,但会在其他地方给你大量的重复.使用DISTINCT或GROUP BY对它们进行排序将是另一个重要的性能负载.检查SQL Server Management Studio中的执行计划! (12认同)
  • 与OR等效的IN子句适用于参数/值列表,但不适用于子查询,这些子查询通常被视为联接。 (2认同)

lin*_*ico 35

好吧,我相信这是一个"老而金"的问题.答案是:"这取决于!".演出是如此微妙的主题,说:"永远不要使用子查询,永远加入"是太愚蠢了.在以下链接中,您将找到一些我发现非常有用的基本最佳实践: 这里1 这里2 在这里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 
)
Run Code Online (Sandbox Code Playgroud)

执行需要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
)
Run Code Online (Sandbox Code Playgroud)

花了0.0256s

好SQL,好.

  • 子查询生成的临时表较小。因此,由于要检入的数据较少,因此执行速度更快。 (5认同)
  • 有趣的是,您能解释一下如何添加固定的GROUP BY吗? (3认同)
  • 我认为在第一个查询中,外部查询和子查询之间具有共享变量,因此对于主查询中的每一行,都会执行子查询,而在第二个查询中,子查询仅执行一次,因此性能得以提高。 (2认同)
  • Sql 服务器和 MySql 和 ...Sql(NoSql 除外)在基础设施上非常相似。我们有一种查询优化引擎,它可以将 IN (...) 子句转换为连接(如果可能的话)。但是,当您在索引良好的列(基于其基数)上进行分组时,速度会快得多。所以这确实取决于具体情况。 (2认同)
  • 你确定缓冲区是干净的吗?这是很有意义的,如果你一个接一个地运行这两个查询,性能将会有巨大的差异 (2认同)

HLG*_*GEM 10

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

我不希望它们如此可怕地不同,在使用相关子查询时,使用连接而不是子查询可以获得真正的大量性能提升.

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


小智 8

性能取决于您正在执行的数据量...

如果较少,则大约20k的数据。JOIN效果更好。

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

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

我测试的所有这些条件和表均具有正确的索引。


Vin*_*mir 6

我知道这是一篇旧文章,但我认为这是一个非常重要的主题,尤其是现在我们拥有 10M+ 记录并谈论 TB 级数据。

我还将阐述以下观点。我的表 ([data]) 中有大约 45M 条记录,[cats] 表中有大约 300 条记录。我为我将要讨论的所有查询建立了广泛的索引。

考虑示例 1:

UPDATE d set category = c.categoryname
FROM [data] d
JOIN [cats] c on c.id = d.catid
Run Code Online (Sandbox Code Playgroud)

与示例 2 相比:

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

示例 1 的运行时间约为 23 分钟。示例 2 大约需要 5 分钟。

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

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

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


Luc*_*ero 5

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

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


one*_*hen 5

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

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