在JOIN子句和WHERE子句中放置条件之间是否存在差异(性能,最佳实践等)?
例如......
-- Condition in JOIN
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD
ON CUS.CustomerID = ORD.CustomerID
AND CUS.FirstName = 'John'
-- Condition in WHERE
SELECT *
FROM dbo.Customers AS CUS
INNER JOIN dbo.Orders AS ORD
ON CUS.CustomerID = ORD.CustomerID
WHERE CUS.FirstName = 'John'
您更喜欢哪个(也许是为什么)?
答案 0 :(得分:132)
关系代数允许WHERE
子句和INNER JOIN
中谓词的可互换性,因此使用INNER JOIN
子句的WHERE
查询可以使优化器重新排列谓词这样在JOIN
过程中可能已被排除。
我建议您以最易读的方式编写查询。
有时这包括使INNER JOIN
相对“不完整”,并在WHERE
中添加一些标准,以便更轻松地维护过滤条件列表。
例如,而不是:
SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
ON ca.CustomerID = c.CustomerID
AND c.State = 'NY'
INNER JOIN Accounts a
ON ca.AccountID = a.AccountID
AND a.Status = 1
写:
SELECT *
FROM Customers c
INNER JOIN CustomerAccounts ca
ON ca.CustomerID = c.CustomerID
INNER JOIN Accounts a
ON ca.AccountID = a.AccountID
WHERE c.State = 'NY'
AND a.Status = 1
但这当然取决于。
答案 1 :(得分:108)
对于内连接,我没有真正注意到差异(但与所有性能调整一样,您需要根据您的条件检查数据库)。
但是,如果使用左连接或右连接,则放置条件会产生巨大差异。例如,考虑这两个查询:
SELECT *
FROM dbo.Customers AS CUS
LEFT JOIN dbo.Orders AS ORD
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderDate >'20090515'
SELECT *
FROM dbo.Customers AS CUS
LEFT JOIN dbo.Orders AS ORD
ON CUS.CustomerID = ORD.CustomerID
AND ORD.OrderDate >'20090515'
第一个将只提供那些订单日期晚于2009年5月15日的记录,从而将左连接转换为内连接。第二个是给那些记录加上没有订单的任何客户。根据您放置条件的位置,结果集非常不同。 (选择*仅作为示例,当然不应在生产代码中使用。)例外情况是,您只想查看一个表中的记录而不能查看另一个表中的记录。然后使用where子句作为条件而不是连接。
SELECT *
FROM dbo.Customers AS CUS
LEFT JOIN dbo.Orders AS ORD
ON CUS.CustomerID = ORD.CustomerID
WHERE ORD.OrderID is null
答案 2 :(得分:23)
大多数RDBMS产品都会以相同的方式优化两个查询。在Peter Gulutzan和Trudy Pelzer的“SQL Performance Tuning”中,他们测试了多个品牌的RDBMS,发现没有性能差异。
我更喜欢将连接条件与查询限制条件分开。
如果您正在使用OUTER JOIN
,有时需要在条件中添加条件。
答案 3 :(得分:11)
JOIN发生后将在哪里过滤。
过滤JOIN以防止在JOIN过程中添加行。
答案 4 :(得分:3)
我更喜欢JOIN加入完整的表/视图,然后使用WHERE来引入结果集的谓词。
感觉语法清晰。
答案 5 :(得分:2)
我在连接过滤时通常会看到性能提升。特别是如果您可以加入两个表的索引列。您应该能够减少逻辑读取,大多数查询也会这样做,也就是说,在高容量环境中,性能指标要比执行时间好得多。
当有人展示他们的SQL基准测试并且他们在开发服务器上午夜执行了50,000次sproc的两个版本并比较平均时间时,我总是有点逗乐。
答案 6 :(得分:0)
将条件放在连接中对我来说似乎是“语义上的错误”,因为这不是JOINs的“for”。但那是非常定性的。
其他问题:如果您决定从内部联接切换到右联接,则将条件置于JOIN内部可能会导致意外结果。
答案 7 :(得分:0)
当你有一张更大的桌子时,我认为加入更快。它确实没那么大差别,特别是如果你正在处理一个相当小的表。当我第一次了解连接时,我被告知连接中的条件就像where子句条件一样,如果where子句具体关于哪个表来执行条件,我可以互换使用它们。
答案 8 :(得分:0)
同意第二多投票的答案,即使用 LEFT JOIN
或 RIGHT JOIN
时会有很大的不同。实际上,下面的两个语句是等价的。因此,您可以看到 AND
子句在 JOIN
之前进行过滤,而 WHERE
子句在 JOIN
之后进行过滤。
SELECT *
FROM dbo.Customers AS CUS
LEFT JOIN dbo.Orders AS ORD
ON CUS.CustomerID = ORD.CustomerID
AND ORD.OrderDate >'20090515'
SELECT *
FROM dbo.Customers AS CUS
LEFT JOIN (SELECT * FROM dbo.Orders WHERE OrderDate >'20090515') AS ORD
ON CUS.CustomerID = ORD.CustomerID
答案 9 :(得分:-1)
最好在Join中添加条件。性能比可读性更重要。对于大型数据集,这很重要。