JOIN比WHERE更快吗?

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

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个视图的所有文档。 我想到的两个解决scheme是:

 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等…)

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

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

MSSql服务器按以下顺序执行查询(这应该给你一个关于WHERE和JOIN子句的function的概念)

Microsoft Sql Server查询stream程订单

以下是从关于Microsoft SQL Server, Microsoft SQL Server 2005内部的优秀丛书:T-SQL查询可以在这里find

(步骤8)SELECT(步骤9)DISTINCT(步骤11)
(第1步)从left_table
(步骤3) join_type JOIN right_table
(第2步)在join_condition上
(步骤4)where where_condition
(第5步)GROUP BY group_by_list
(步骤6)WITH [CUBE | ROLLUP]
(第7步)有having_clause
(步骤10)ORDER BY order_by_list

没有办法正确回答这个问题,而不限制目标数据库。

对于MS-SQL,这两个查询的结果都是相同的执行计划,但请记住:

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

由于很容易忘记WHERE子句中的连接条件,并最终导致一个讨厌的交叉连接,所以确实存在风险。

至less在MySQL中,它们都将被优化到相同的查询。

这是一个使用INNER JOIN语法的“标准”,虽然实际上是相同的。 应该使用的主要原因是为了清晰和移动的目的,因为它与OUTER JOIN语法一致。

如果您正在专门讨论SQL Server,那么您一定要使用INNER JOIN语法。 除了(个人意见警报!)更容易阅读和意图更清楚,从SQL Server 2005,没有外部连接的等效语法。 2005年默认不支持* =和= *语法 – 您需要启用兼容模式来支持它。 它最终会被删除,可能会在下一个版本(或可能不是!

意即:

  • 如果您需要将内部连接更改为外部连接,则需要重写(argh)或启用compat模式(yuk)
  • 没有compat模式,你不能与你如何实现不同types的连接(内部vs外部)一致,从而导致维护噩梦(在两个在一个查询中组合的情况下,一些非直观的行为)。

还要注意,与stream行的看法相反,两者并不相同。 有些东西比较笨拙,有些则根本不可能。 Kalen Delaney的Inside SQL Server 2000涵盖了一些例子; 不确定新版本是否会这样做,因为反正这个连接语法已经被废弃了。

显式连接更容易维护,因为查询的意图更清晰。 而且它们不会受到意外的交叉连接,所以如果你在查询中有一个交叉连接,维护者知道它打算在那里。

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

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

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

我想这也没有什么不同。 要确定你可以检查这两个查询的解释计划是否一致。 为了查看MySQL中的解释计划,您必须在语句前面加上“explain”关键字,例如:

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

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

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