最好在你的ON子句中加入更多的逻辑,还是只有最小的必要条件?

时间:2009-04-30 21:00:48

标签: sql sql-server

鉴于这两个问题:

Select t1.id, t2.companyName 
from table1 t1 
  INNER JOIN table2 t2 on t2.id = t1.fkId 
WHERE t2.aField <> 'C' 

或者:

Select t1.id, t2.companyName 
from table1 t1 
  INNER JOIN table2 t2 on t2.id = t1.fkId  and t2.aField <> 'C'

这两者之间是否存在明显差异?在我看来,条款“t2.aField&lt;&gt;'C'”将在t2中符合连接条件的每一行上运行,无论如何。我不对吗?

更新:我在SQL Server中执行了“包含实际执行计划”。这两个查询完全相同。

6 个答案:

答案 0 :(得分:4)

我更喜欢使用Join标准来解释表格如何连接在一起。 所以我将附加条款放在where部分。

我希望(尽管我没有统计数据),无论您使用何种语法,SQL Server都能够聪明地找到最佳查询计划。

但是,如果您的索引也有id,并且其中包含aField,我建议将它们放在内连接条件中。

在这两个(或3个)场景中查看查询计划会很有趣,看看会发生什么。好问题。

答案 1 :(得分:3)

有区别。您应该为两个选项执行EXPLAIN PLAN并详细查看。

至于更简单的解释: WHERE子句只有在连接两个表后才会执行,因此它对从连接返回的每一行执行,而不是从table2中每个都执行。

性能方面最好尽早消除不需要的结果,因此连接的行数应该更少,以及后续处理的子句或其他操作。

在第二个例子中,要连接在一起的行有两列必须相同,所以它通常会得到与第一列不同的结果。

答案 2 :(得分:2)

取决于。

SELECT
  t1.foo,
  t2.bar
FROM
  table1 t1
  LEFT JOIN table2 t2 ON t1.SomeId = t2.SomeId
WHERE
  t2.SomeValue IS NULL

不同
SELECT
  t1.foo,
  t2.bar
FROM
  table1 t1
  LEFT JOIN table2 t2 ON t1.SomeId = t2.SomeId AND t2.SomeValue IS NULL

它是不同的,因为前者跨越了t2中所有在t2.SomeValue 中具有NULL的记录和来自t1的未在t2中引用的那些记录。后者仅跨越t2.SomeValue中具有NULL的t2记录。

只需对连接条件使用ON子句,对过滤器使用WHERE子句。

答案 3 :(得分:1)

除非将连接条件移动到where子句更改查询的含义(如上面的左连接示例中所示),否则放置它们的位置无关紧要。 SQL会重新安排它们,只要它们可以证明是等价的,你就会得到相同的查询。

话虽如此,我认为这更符合逻辑/可读性。我通常在连接中放置与两个表相关的任何内容,以及在where中过滤的任何内容。

答案 4 :(得分:0)

我更喜欢第一次查询。 SQL服务器将根据您拥有的索引为您的查询使用最佳连接类型,之后将应用WHERE子句。但是你可以同时运行两个查询,查看执行计划,比较并选择最快的(也可以优化添加索引)。

答案 5 :(得分:0)

除非您正在处理单用户应用程序或类似的小型应用程序,否则会产生微不足道的负载,唯一的考虑因素是服务器将如何处理您的查询。

提及查询计划的答案提供了很好的建议。

此外,设置io统计信息以了解您的查询将生成多少读取(我特别喜欢Azder的帖子)。

将每个数据库服务器视为从磁盘到客户端的数据泵。如果它只执行完成工作所需的IO,那么该泵会更快。如果数据在缓存中,它将更快。但是你不希望从磁盘读取超过你需要的东西 - 这将导致你的缓存中有用的数据被挤出,这是没有充分理由的。