JOIN或WHERE中的条件

Ste*_*nan 170 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'
Run Code Online (Sandbox Code Playgroud)

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

Cad*_*oux 144

关系代数允许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
Run Code Online (Sandbox Code Playgroud)

写:

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
Run Code Online (Sandbox Code Playgroud)

但这当然取决于它.

  • 增加它取决于.一切都标榜. (21认同)
  • 这不仅仅是关于干净的查询或可读性,而是关于性能.将条件置于连接中可以使用正确索引的表来提高大量数据的性能. (4认同)
  • @Cade我已经调查了执行计划 - 两种情况都显示相同的成本.我多次运行查询似乎都是相同的时间.以前,我在生产中运行查询并且因为实时用户正在使用数据库而获得显着的性能差异.对不起,这个混乱. (4认同)
  • 这个答案适用于INNER JOIN,但不适用于左/右连接. (4认同)
  • 我只是运行月度销售报告,将 5-6 个表加入数百万条记录。性能提高了 30% - sql server 2012 (2认同)
  • @Shahdat如果你的过滤条件从where子句移动到内部联接,你需要发布那些重要的性能差异,你需要发布这些执行计划. (2认同)

HLG*_*GEM 115

对于内连接,我没有真正注意到差异(但与所有性能调整一样,您需要根据您的条件检查数据库).

但是,如果使用左连接或右连接,则放置条件会产生巨大差异.例如,考虑这两个查询:

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'
Run Code Online (Sandbox Code Playgroud)

第一个将只给出那些订单日期晚于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
Run Code Online (Sandbox Code Playgroud)

  • “从而将左连接转换为内连接”。如何?你能详细说明一下吗? (5认同)
  • @user1451111 或者,更简单地说:`A left join B` 是从 A 连接到来自 B 的每个匹配行的每一行。如果 B 没有匹配的行,那么 A 列有一个值,但该行上 B 的每一列都有一个值显示为 NULL 值。如果你写了 `where B.somecolumn = 'somevalue'` 那么你有一个 NULL (B.somecolumn) 与 'somevalue' 进行比较。与 NULL 相比的任何内容都是假的,因此 A 行没有匹配 B 行的所有行都被消除,并且您获得的结果与 INNER JOIN 给出的结果相同,因此外连接已成为内连接 (2认同)

Bil*_*win 24

大多数RDBMS产品都会以相同的方式优化两个查询.在Peter Gulutzan和Trudy Pelzer的"SQL Performance Tuning"中,他们测试了多个品牌的RDBMS并发现没有性​​能差异.

我更喜欢将连接条件与查询限制条件分开.

如果您OUTER JOIN有时使用,则需要在join子句中添加条件.

  • 我同意你的观点,从语法上来说它更干净,我必须尊重你对那本书的了解和你很高的声誉,但我可以想到上周有 4 个查询,它们的执行计划、CPU 时间和逻辑读取都非常不同我将 where 谓词移至连接。 (2认同)
  • 您在询问最佳做法。一旦测试了特定RDBMS实现的工作原理,其他人就会给出正确的建议:基准测试。 (2认同)

The*_*TXI 10

在JOIN发生后将过滤WHERE.

过滤JOIN以防止在JOIN过程中添加行.

  • 在语义上,它们在INNER JOIN过程中被阻止,但优化器可以随意重新排列INNER JOIN和WHERE谓词,因此优化器可以在以后随意排除它们. (10认同)