【问题标题】:SQL Joins Vs SQL Subqueries (Performance)?SQL 连接与 SQL 子查询(性能)?
【发布时间】:2011-04-20 20:20:44
【问题描述】:

我想知道我是否有类似这样的 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)

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

还有什么时候我应该更喜欢一个而不是另一个?

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

【问题讨论】:

  • @Lucero,这个问题被标记为 sql-server-2008,你提到的帖子被标记为 MySql。你可以推断答案是一样的。两个 RDBMS 的性能优化方式不同。

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


【解决方案1】:

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

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

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

【讨论】:

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

嗯,我相信这是一个“古老但黄金”的问题。答案是:“这取决于!”。 表演是一个如此微妙的主题,以至于说“永远不要使用子查询,总是加入”就太愚蠢了。 在以下链接中,您会发现一些我认为非常有用的基本最佳实践:

我有一个包含 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,好。

【讨论】:

  • 有趣,您能解释一下添加 GROUP BY 是如何解决它的吗?
  • 子查询生成的临时表变小了。因此,由于要签入的数据更少,因此执行速度更快。
  • 我认为在第一个查询中,您在外部查询和子查询之间共享变量,因此对于主查询中的每一行,子查询都会执行,但在第二个查询中,子查询只执行一次,这样性能就会提高。
  • Sql server 与 MySql 和 ...Sql(NoSql 除外)在基础设施上是如此相似。我们有一种查询优化引擎,它可以将 IN (...) 子句转换为 join(如果可能的话)。但是,当您在索引良好的列(基于其基数)上有一个 Group by 时,它会快得多。所以这真的取决于情况。
  • 你确定缓冲区是干净的吗?如果您一个接一个地运行这两个查询,那么性能会有很大差异,这很有意义
【解决方案3】:

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

如果是 20k 左右的数据较少。 JOIN 效果更好。

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

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

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

【讨论】:

    【解决方案4】:

    开始查看执行计划以了解 SQl 服务器如何解释它们的差异。您还可以使用 Profiler 多次实际运行查询并获得差异。

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

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

    【讨论】:

      【解决方案5】:

      性能应该是一样的;在您的表上应用正确的索引和集群更为重要(该主题存在some good resources)。

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

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

          【解决方案7】:

          我知道这是一篇旧文章,但我认为这是一个非常重要的话题,尤其是现在我们有 1000 万多条记录并谈论 TB 级数据。

          我还将强调以下意见。我的表([data])中有大约 45M 条记录,[cats] 表中有大约 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 分钟。

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

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

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

          【讨论】:

            【解决方案8】:

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

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

            【讨论】:

            • “Exists 过滤器的执行速度可能最快”——我认为可能不会,尽管明确的答案需要针对实际数据进行测试。如果存在具有相同查找值的多行,Exists 过滤器可能会更快 - 因此,如果查询正在检查其他员工是否已从同一部门记录,则存在过滤器可能会运行得更快,但在查找部门时可能不会表。
            • 在最后一种情况下它会运行得更慢吗?
            • 这取决于优化器 - 在某些情况下,它可能会,但通常我会期望非常相似的性能。
            猜你喜欢
            • 2019-08-06
            • 1970-01-01
            • 2012-10-29
            • 2013-04-26
            • 1970-01-01
            • 1970-01-01
            • 2016-08-19
            • 1970-01-01
            • 2017-03-15
            相关资源
            最近更新 更多