【问题标题】:Is a JOIN faster than a WHERE?JOIN 比 WHERE 快吗?
【发布时间】:2010-11-10 22:10:15
【问题描述】:

假设我有两个链接的表(一个有一个外键到另一个):

CREATE TABLE Document (
  Id INT PRIMARY KEY,
  Name VARCHAR 255
)

CREATE TABLE DocumentStats (
  Id INT PRIMARY KEY,
  DocumentId INT, -- this is a foreign key to table Document
  NbViews INT
)

我知道,这不是最聪明的做事方式,但这是我能想到的最好的例子。

现在,我想获取所有查看次数超过 500 的文档。我想到的两个解决方案是:

SELECT *
FROM Document, DocumentStats
WHERE DocumentStats.Id = Document.Id
  AND DocumentStats.NbViews > 500

或:

SELECT *
FROM Document
INNER JOIN DocumentStats ON Document.Id = DocumentStats.Id
WHERE DocumentStats.NbViews > 500

这两个查询是等效的,还是有一种方法比另一种方法好得多?如果有,为什么?

编辑:按照答案中的要求,这个问题是针对 SQL Server 的,但我想知道它是否与其他数据库引擎(MySQL 等)不同。

【问题讨论】:

  • 什么数据库? SQL 女士、MySQL、SQLite、甲骨文...?
  • 这被称为显式连接与隐式连接,之前有人问过:stackoverflow.com/questions/44917/…
  • @Theo:主要是 MSSQL,但我也会对其他人感兴趣... @Paolo:谢谢,我不知道它是那样的调用。我尝试使用 JOIN vs WHERE 进行搜索,但找不到答案。
  • 在不同的搜索条件下两次将其放入系统中没有什么坏处。 :)

标签: sql performance join where-clause


【解决方案1】:

“JOIN”与“WHERE”的性能...一切都取决于数据库引擎为您优化查询的能力。它将考虑您在返回的列上可能拥有的任何索引,并考虑 WHERE 和 JOIN 子句的性能也归结为物理数据库文件本身及其碎片级别,甚至是您用于存储数据库文件的存储技术.

SQL 服务器按以下顺序执行查询(这应该让您了解 WHERE 和 JOIN 子句的功能)

Microsoft SQL Server 查询处理顺序

以下内容摘自关于 Microsoft SQL Server 的优秀系列书籍,Inside Microsoft SQL Server 2005: T-SQL Querying,可以在here找到

(第 8 步)选择(第 9 步)DISTINCT(第 11 步)
(第 1 步)从 left_table
(第 3 步) join_type 加入 right_table
(步骤 2)ON join_condition
(步骤 4)WHERE where_condition
(第 5 步)按组分组 group_by_list
(第 6 步) WITH [CUBE|ROLLUP]
(第 7 步)HAVING have_clause
(第 10 步)按 order_by_list

排序

【讨论】:

  • 啊,喜欢这个答案!通过反复试验发现SQL S.首先执行ON,然后执行WHERE,最后执行HAVING。通常无关紧要,除非在涉及 NULL 的某些情况下 - 在 ON 或 WHERE 处具有过滤条件可以在这种情况下产生 big 差异。现在我想问一下,这种行为是 ANSI 标准规定的还是 SQL Server 特定的?如果您不确定,我可能会就此提出问题!
  • 澄清:“这种行为”是指先评估 ON,然后评估 WHERE 的行为。 Theo 在他的回答中说 SQLite 首先将 JOIN...ON 转换为 WHERE 子句。如果这是真的(不知道,现在无法验证),那么首先评估 ON,WHERE 第二个可能非常特定于 SQL Server(可能也是 Sybase)。
  • 此查询执行顺序是 Microsoft SQL Server 执行查询的方式。
【解决方案2】:

理论上,不,它不应该更快。查询优化器应该能够生成相同的执行计划。但是,一些数据库引擎可以为其中一个生成更好的执行计划(对于这样一个简单的查询不太可能发生,但对于足够复杂的查询)。您应该测试两者并查看(在您的数据库引擎上)。

【讨论】:

  • +1 用于推荐测试 OP 的特定案例。分析胜过。
  • 我同意。我经常尝试查询的 JOIN 和 WHERE 版本,看看哪个执行得最好。有时 JOIN 更快,有时 WHERE - 这取决于查询。
【解决方案3】:

显式连接更易于维护,因为查询的意图更加清晰。此外,它们不会受到意外交叉连接的影响,因此如果您在查询中有交叉连接,维护者就知道它本来应该在那里。

如果您需要使用外连接,您应该知道 *= 语法在 SQL Server 中已被弃用,并且很快将被删除。此外,它目前不能一直按预期运行,并且可能无法给出正确的结果,因此永远不要使用。混合显式外连接和 where 子句连接(隐式连接)会使维护人员更难阅读和理解查询。

【讨论】:

    【解决方案4】:

    如果您专门讨论 SQL Server,那么您绝对应该使用 INNER JOIN 语法。除了(个人意见警告!)更易于阅读和意图更清晰之外,从 SQL Server 2005 开始,外连接没有等效的语法。 2005 年默认不支持 *= 和 =* 语法——您需要启用兼容模式才能支持它。它最终会被删除,可能会在下一个版本发布(或者可能不会!)

    这意味着:

    • 如果您需要将查询从内部联接更改为外部联接,则需要重写 (argh) 或启用兼容模式 (yuk)
    • 如果没有兼容模式,您将无法与实现不同类型连接(内部与外部)的方式保持一致,从而导致维护噩梦(并且,如果将两者组合在一个查询中,某些行为是非直观)。

    另请注意,与流行的看法相反,两者等价。有些事情要尴尬得多,有些事情根本不可能。 Kalen Delaney 的 Inside SQL Server 2000 涵盖了一些示例;不确定新版本是否可以,因为无论如何都不推荐使用该连接语法。

    【讨论】:

      【解决方案5】:

      我想这也没有什么不同。为了确保您可以检查这两个查询的解释计划是否相同。为了查看 MySQL 中的解释计划,您必须在语句之前放置“解释”关键字,例如:

      EXPLAIN
      SELECT *
      FROM Document, DocumentStats
      WHERE DocumentStats.Id = Document.Id
        AND DocumentStats.NbViews > 500
      

      我确信 MSSQL 中也存在等价物。

      顺便说一句: 这看起来是 1:1 的关系,所以我只需将 nbviews 属性直接包含在 Document 表中,因此您可以保存一个联接。

      【讨论】:

        【解决方案6】:

        使用 Sqlite 时:where-syntax 稍微快一些,因为 Sqlite 在执行查询之前首先将 join-syntax 转换为 where-syntax。

        【讨论】:

        • 真的很有趣。您能否为这种行为提供参考?这意味着将过滤条件放在 ON 子句而不是 WHERE 上,这会在 SQL Server 上给出不同的结果,在这里将完全相同!
        • 能否提供参考?
        【解决方案7】:

        使用 INNER JOIN 语法是一个“标准”,尽管实际上是等效的。应该使用它的主要原因是为了清晰和移动性,因为它与 OUTER JOIN 语法一致。

        【讨论】:

          【解决方案8】:

          如果不限于目标数据库,就无法正确回答这个问题。

          对于 MS-SQL,两个查询都会产生相同的执行计划,但请记住:

          SELECT *
          FROM Document, DocumentStats
          WHERE DocumentStats.Id = Document.Id
            AND DocumentStats.NbViews > 500
          

          真的很冒险,因为很容易忘记 WHERE 子句中的连接条件并最终得到一个讨厌的交叉连接。

          【讨论】:

            【解决方案9】:

            在 MSSQL 中,两个查询都编译为相同的执行计划,因此没有区别。它更多的是关于可读性 - 我认为 JOIN 更容易阅读,所以我使用它。

            【讨论】:

              【解决方案10】:

              至少在 MySQL 中,它们都将针对相同的查询进行优化。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2023-01-30
                • 2018-07-10
                • 2010-11-17
                • 2011-07-29
                • 2016-12-12
                • 2013-02-07
                • 1970-01-01
                • 2014-10-01
                相关资源
                最近更新 更多