假设我有两个链接的表(一个具有另一个的外键):
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等等)答案 0 :(得分:40)
理论上,不,它不应该更快。查询优化器应该能够生成相同的执行计划。但是,一些数据库引擎可以为其中一个生成更好的执行计划(这种简单查询不太可能发生,但对于复杂的查询而言)。您应该测试两者并查看(在您的数据库引擎上)。
答案 1 :(得分:17)
“JOIN”与“WHERE”的表现......一切都取决于数据库引擎能够为您优化查询的程度。它将考虑您在返回的列上可能具有的任何索引,并认为WHERE和JOIN子句的性能也归结为物理数据库文件本身及其碎片级别,甚至是用于存储数据库文件的存储技术。
MSSql服务器按以下顺序执行查询(这应该让您了解WHERE和JOIN子句的功能)
以下内容摘自有关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年不支持* =和= *语法 - 您需要启用兼容模式来支持它。它最终会被删除,可能会在下一个版本中发布(或者可能不会!)
这意味着:
另请注意,与普遍看法相反,两者不等价。有些事情更尴尬,有些事情根本不可能。 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属性,因此您可以保存连接。