JOIN比WHERE更快吗?

时间:2009-07-15 07:31:29

标签: sql performance join where-clause

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

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

两个查询都是等价的,还是有一种方法比另一种更好?如果是这样,为什么?

我知道我的例子并不完美,而且查询可能需要一些调整,但我希望你明白这一点;)

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

10 个答案:

答案 0 :(得分:40)

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

答案 1 :(得分:17)

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

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

Microsoft Sql Server查询流程订单

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

  

(步骤8)SELECT(步骤9)DISTINCT(步骤11)    
  (步骤1)FROM left_table
(步骤3)    join_type JOIN right_table
(步骤2)ON join_condition
(步骤4)WHERE    where_condition
(步骤5)GROUP BY group_by_list
(步骤6)WITH [CUBE | ROLLUP]
(步骤7)HAVING    having_clause
(步骤10)ORDER BY order_by_list

答案 2 :(得分:12)

无法在不限制目标数据库的情况下正确回答此问题。

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

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

真的很冒险,因为很容易忘记WHERE子句中的连接条件,最终会遇到令人讨厌的交叉连接。

答案 3 :(得分:4)

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

答案 4 :(得分:2)

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

答案 5 :(得分:2)

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

答案 6 :(得分:2)

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

如果您需要使用外连接,您应该知道在SQL Server中不推荐使用* =语法,很快就会删除它。此外,它目前不能按预期运行,可能无法给出正确的结果,因此不应使用。混合显式外连接和where子句连接(隐式连接)使得查询更难以让维护者阅读和理解。

答案 7 :(得分:2)

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

这意味着:

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

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

答案 8 :(得分:1)

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

答案 9 :(得分:1)

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

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

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

顺便说一下: 这看起来像是1:1关系,因此我只是直接在Document表中包含nbviews属性,因此您可以保存连接。