代码之家  ›  专栏  ›  技术社区  ›  Wookai

JOIN比WHERE快吗?

  •  52
  • Wookai  · 技术社区  · 17 年前

    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
    )
    

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

    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等)不同。

    10 回复  |  直到 6 年前
        1
  •  48
  •   Dale K    6 年前

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

        2
  •  20
  •   Dale K    6 年前

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

    SQL server按以下顺序执行查询(这将使您了解WHERE和JOIN子句的功能)

    Microsoft SQL Server查询进程顺序

    以下内容摘自有关Microsoft SQL Server的优秀丛书, Microsoft SQL Server 2005内部:T-SQL查询 可以找到 here

    (步骤8)选择(步骤9)不同(步骤11) <顶级规格>&书信电报;选择列表>
    (步骤1)从 左表
    (步骤3) 参加 右表
    (步骤2)打开 连接条件
    (步骤4)其中 你的条件在哪里
    (步骤5)分组方式 分组列表
    (步骤6)使用[CUBE | ROLLUP]
    (步骤7)具有
    (步骤10)按以下方式订购 按订单列表订购

        3
  •  13
  •   Sam Saffron James Allen    17 年前

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

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

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

    这是非常危险的,因为很容易忘记WHERE子句中的连接条件,并以一个糟糕的交叉连接结束。

        4
  •  4
  •   Greg    17 年前

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

        5
  •  2
  •   Sev    17 年前

    使用内部联接语法是一种“标准”,尽管实际上是等效的。应该使用它的主要原因是为了清晰和移动性,因为它与外部连接语法一致。

        6
  •  2
  •   Theo    17 年前

    使用Sqlite时:where语法稍微快一点,因为Sqlite在执行查询之前首先将连接语法转换为where语法。

        7
  •  2
  •   Cowan    17 年前

    如果您专门谈论SQL Server,那么您肯定应该使用内部连接语法。除了(个人意见提醒!)更易于阅读和更清晰的意图之外,从SQLServer2005开始,外部联接没有等效的语法。在2005年,默认情况下不支持*=和=*语法——您需要启用兼容模式来支持它。它最终将被删除,可能会在下一个版本中删除(也可能不会!)

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

    还要注意的是,与流行的观点相反,这两种观点是 相等的有些事情要尴尬得多,有些根本不可能。卡伦·德莱尼氏 内部SQL Server 2000 包括一些例子;不确定较新版本是否支持,因为该连接语法已被弃用。

        8
  •  2
  •   Carl Manaster    17 年前

    显式连接更容易维护,因为查询的意图更清楚。此外,它们也不会受到意外交叉连接的影响,因此如果查询中有交叉连接,则维护人员知道它本来就在那里。

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

        9
  •  1
  •   SqlRyan    17 年前

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

        10
  •  1
  •   samson    17 年前

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

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

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

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