在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'
你更喜欢哪一个(也许为什么)?
关系代数允许WHERE子句和INNER JOIN中的谓词互换性,因此即使是带有WHERE子句的INNER JOIN查询也可以由优化器重新安排谓词,以便在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
当然,这要视情况而定。
对于内部连接,我并没有注意到有什么不同(但是与所有性能调优一样,您需要在您的条件下检查数据库)。
但是,如果使用左连接或右连接,将条件放在哪里会产生巨大的差异。例如,考虑以下两个查询:
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