JOIN或WHERE中的条件

时间:2009-06-19 16:49:47

标签: sql performance

在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'

您更喜欢哪个(也许是为什么)?

10 个答案:

答案 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 JOINRIGHT 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中添加条件。性能比可读性更重要。对于大型数据集,这很重要。