【问题标题】:Can I get better performance using a JOIN or using EXISTS?我可以使用 JOIN 或 EXISTS 获得更好的性能吗?
【发布时间】:2010-09-18 15:04:57
【问题描述】:

我有两个表机构和结果,我想看看是否有任何机构的结果,这样我就可以排除那些没有结果的机构。

我可以使用 JOIN 或 EXISTS 获得更好的性能吗?

谢谢你,
-尼梅什

【问题讨论】:

  • 这不是一个真正的问题,因为它非常通用。他至少需要指定至少一点上下文。
  • 我添加了主观标签,因为这个问题非常笼统。
  • @NImesh——在这种特殊情况下,细节是你的朋友。您可以提供的详细信息越多,您就越有可能获得有用的、建设性的答案。哪种类型的 SQL(即 Oracle 或 MS SQL Server)?您要查询的表的结构是什么?等等等等等等。
  • 我希望我的编辑是合理的。如果这不符合您最初问题的精神,请随意回滚。
  • 您应该使用每种方法显示完整的 SQL 查询,以便我们更好地了解您要执行的操作。

标签: sql performance


【解决方案1】:

如果您指的是使用左(或右)外连接或不存在的子查询,我相当肯定左外连接在性能方面胜出。例如:

SELECT t1.* FROM table1 t1 LEFT OUTER JOIN table2 t2 ON t1.id = t2.id WHERE t2.id IS NULL

以上应该比等效的子查询更快,如果您专门指的是存在 - 好吧,在结构允许的情况下,内连接将始终是首选选项。

【讨论】:

    【解决方案2】:

    视情况而定。

    最终,两者的用途完全不同。

    您加入 2 个表以访问相关记录。如果您不需要访问相关记录中的数据,则无需加入它们。

    EXISTS 可用于确定给定数据集中是否存在令牌,但不允许您访问相关记录。

    发布您想到的两种方法的示例,我可能会给您一个更好的想法。


    如果你想要一个有结果的机构列表,使用你的两个表机构和结果,这个查询将是最有效的:

    select Institutions.institution_name 
    from Institutions
    inner join Results on (Institutions.institution_id = Results.institution_id)
    

    如果您有一个机构 ID,并且只想知道它是否有结果,使用 EXISTS 可能会更快:

    if exists(select 1 from Results where institution_id = 2)
      print "institution_id 2 has results"
    else
      print "institution_id 2 does not have results"
    

    【讨论】:

    • 由于您的解释很好,“可能更快”是对哪个选项更快的问题的简短回答。
    【解决方案3】:

    我会说 JOIN 比较慢,因为只要 EXISTS 调用找到某些内容,您的查询执行就会停止,而 JOIN 会一直持续到最后。

    编辑:但这取决于查询。这应该根据具体情况来判断。

    【讨论】:

    • 在他的情况下,他正在寻找缺少数据,因此仍需要扫描整个结果表(或者,希望是索引)
    • 是的。我在他澄清之前发布了这个。我不妨删除这个答案。不知道我是否应该这样做。 :)
    • 很高兴您没有删除它 - 它提供了有用的见解! (存在短路...)
    【解决方案4】:

    您是否使用 EXISTS 作为相关子查询的一部分?如果是这样,连接几乎总是会更快。

    您的数据库应该有对查询进行基准测试的方法。使用它们来查看哪个查询运行得更快。

    【讨论】:

      【解决方案5】:

      无论是否存在性能差异,您都需要使用更适合您的目的。您的目的是获取机构列表(而不是结果 - 您不需要额外的数据)。所以选择没有结果的机构...翻译 - 使用 EXISTS。

      【讨论】:

        【解决方案6】:

        如果您想要没有结果的机构,那么“Where Not Exists”子查询会更快,因为它会在为那些有结果的机构找到单个结果时立即停止...

        如果您希望机构有结果,但您实际上并不想要结果,同样的事情。使用“存在位置”子查询。它会在找到单个结果后立即停止...这也确保结果集每个机构只有一条记录,而如果您的机构有多个结果,则使用join 方法需要您添加“distinct”关键字或“Group By”子句,以消除从与单个机构匹配的多个结果记录中产生的重复 cartesion 产品行。

        如果您需要结果,请执行 JOIN - 如果您不想看到没有结果的机构,请执行内部联接;如果您想查看所有机构,包括没有结果的机构,请执行外部联接。

        【讨论】:

          【解决方案7】:

          这取决于您的优化器。我在 Oracle 10g 和 11g 中尝试了以下两个。在 10g 中,第二个稍快一些。在 11g 中,它们是相同的。

          但是,#1 实际上是对 EXISTS 子句的误用。使用连接查找匹配项。

          select *
          from
            table_one t1
          where exists (
                       select *
                       from table_two t2
                       where t2.id_field = t1.id_field
                       )
          order by t1.id_field desc
          
          
          select t1.*
          from 
            table_one t1
           ,table_two t2
          where t1.id_field = t2.id_field
          order by t1.id_field desc 
          

          【讨论】:

          • 也许如果在第一个选项中子查询只返回 t2.id_field 而不是 *,它可以补偿时间。有时回报的大小也会影响业绩。特别是在这种情况下,情况略有不同。祝你好运,谢谢!!!
          • 第二个查询的样式已被弃用。不要那样做。并且不要使用 splats。但一定要使用模式。
          【解决方案8】:

          根据语句、统计信息和数据库服务器,可能没有区别——可能会产生相同的优化查询计划。

          数据库在后台连接表的方式基本上有 3 种:

          • 嵌套循环 - 对于一个比第二个大得多的表。较小表中的每一行都会检查较大表中的每一行。

          • 合并 - 用于具有相同排序顺序的两个表。两者都按顺序运行,并在它们对应的位置匹配。

          • 哈希 - 其他所有内容。临时表用于建立匹配。

          通过使用存在,您可以有效地强制查询计划执行嵌套循环。这可能是最快的方法,但您确实希望查询规划器来决定。

          我会说您需要编写两个 SQL 语句并比较查询计划。您可能会发现它们会根据您拥有的数据而发生很大变化。

          例如,如果 [Institutions] 和 [Results] 的大小相似,并且都聚集在 InstitutionID 上,则合并连接将是最快的。如果 [Results] 比 [Institutions] 大得多,则嵌套循环可能会更快。

          【讨论】:

            【解决方案9】:

            实际上,从您对问题的模糊描述来看,在我看来,NOT IN 查询是最明显的编码方式:

            SELECT *
              FROM Institutions
              WHERE InstitutionID NOT IN (
                 SELECT DISTINCT InstitutionID
                   FROM Results
                 )
            

            【讨论】:

            • 你到底为什么要添加一个独特的?数字 1 要么在此列表中(1、1、1、2、2、5、5、7),要么不在。对列表进行排序和过滤是完全不重要的。事实上,当我在 10.2.0.3 中这样做时,它完全被忽略了。
            • 根据我查看执行计划的经验,无论您是否有 DISTINCT 关键字,Oracle 都会将其过滤为唯一值。因此我喜欢包含它,因为它使代码的目的更清晰。
            【解决方案10】:

            LEFT OUTER JOIN 的性能往往比 NOT EXISTS** 好,但在您的情况下,您想做 EXISTS 并且使用简单的 INNER JOIN 并不能完全复制 EXISTS 行为。如果您有一个机构的多个结果,执行 INNER JOIN 将返回该机构的多行。您可以通过使用 DISTINCT 来解决这个问题,但无论如何 EXISTS 的性能可能会更好。

            ** 对于不熟悉此方法的人:

            SELECT
                 MyTable.MyTableID
            FROM
                 dbo.MyTable T1
            LEFT OUTER JOIN dbo.MyOtherTable T2 ON
                 T2.MyTableID = T1.MyTableID
            WHERE
                 T2.MyOtherTableID IS NULL
            

            等价于

            SELECT
                 MyTable.MyTableID
            FROM
                 dbo.MyTable T1
            WHERE NOT EXISTS (SELECT * FROM MyOtherTable T2 WHERE T2.MyTableID = T1.MyTableID)
            

            假设 MyOtherTableID 是 NOT NULL 列。不过,第一种方法通常比 NOT EXISTS 方法执行得更快。

            【讨论】:

            • 参见dba.stackexchange.com/a/4010/630 + 后续链接。 LEFT JOIN 可能需要一个 DISTINCT,它也会让你大吃一惊。 通常 EXISTS 更快且语义正确
            【解决方案11】:

            如果 RESULTS 表中每个 INSTITUTION 包含多于一行,EXISTS() 的额外好处是不需要您选择不同的机构。

            至于性能,我看到joins, IN(), and EXISTS() 在各种用途中都是最快的。要找到最适合您的方法,您必须进行测试。

            【讨论】:

              【解决方案12】:

              在上述情况下,Exists 语句的运行速度比 Joins 快。 Exists 会给你一个记录,也会节省时间。 在连接的情况下,记录的数量会更多,并且必须使用所有记录。

              【讨论】:

              • 欢迎来到stackoverflow。这个问题已经很老了,并且被很好地涵盖了。在复活这样一个旧线程之前,请确保您的回复为对话增加了一些重要的内容,
              猜你喜欢
              • 1970-01-01
              • 2011-01-11
              • 1970-01-01
              • 2020-05-05
              • 2014-08-23
              • 2014-04-28
              • 1970-01-01
              • 2012-11-21
              • 2017-11-17
              相关资源
              最近更新 更多