MSSQL - 在 where 和 on 子句性能上添加条件

Posted

技术标签:

【中文标题】MSSQL - 在 where 和 on 子句性能上添加条件【英文标题】:MSSQL - Adding condition on the where and on clause performance 【发布时间】:2020-12-17 09:34:41 【问题描述】:

考虑以下两个查询:

select *
from 
   table1 t1
      left join
   table2 t2
      on t1.Id = t2.t1Id and (t1.Status = 1 or t2.Id is not null)

还有这个

select *
from 
   table1 t1
      left join
   table2 t2
      on t1.Id = t2.t1Id 
where
   t1.Status = 1 or t2.Id is not null

第一个在 2 秒内运行。 2分钟内第二个。执行计划不应该一样吗?

【问题讨论】:

它们产生不同的结果集。从逻辑上讲,他们不可能有完全相同的计划。 请详细说明。结果有什么不同。 使用declare @table1 table (Id int, Status int) declare @table2 table (Id int, T1Id int) insert into @table1 (ID,Status) values (1,1), (2,2) insert into @table2 (Id, T1Id) values (1,1) 作为表 1 和 2,第一个查询产生 2 行。第二个产生 1。 @AthanasiosKataras - 这是因为您使用的是 LEFT JOIN。第一个查询将返回表 2 中没有的具有 NULL 值的行。第二个查询将不返回这些行。如果是 INNER JOIN,它们本质上是相同的查询。 我知道我编写查询的方式会首先带来空值,但它们最终会被 where 子句过滤掉,有效地返回相同的结果。我希望查询计划能够解决这个问题并产生相同的计划。 【参考方案1】:

查询计划不同,因为查询(和结果)不同。

您使用的是 LEFT JOIN,因此第一个查询将返回表 2 中没有的具有 NULL 值的行。 第二个查询不会返回这些行。

如果是 INNER JOIN,它们本质上是同一个查询。

【讨论】:

我认为它不会产生不同的结果。无论是在表连接期间应用过滤器还是在它们连接后应用过滤器,结果都应该是相同的。 再次阅读我的帖子 - 它解释了为什么它会产生不同的结果,并且不信者达米安在原始帖子的评论中为您提供了示例数据。 好的,知道了。我形象化了。它。在第一种情况下不为空,不适用于结果集,但适用于值本身。 第一个查询过滤从 TABLE2 返回的数据,第二个查询过滤结果中出现的内容。左连接将返回表 1 中的记录显示 NULL 的记录,但表 2 中的记录不显示。 INNER JOIN(或 WHERE 过滤器)不会在结果中返回不符合该条件的记录。 @AthanasiosKataras - 很抱歉同时发布...是的,没错。【参考方案2】:

下面的查询根据“ON 子句”条件返回所有“Table1”结果以及其他匹配列。

select * from table1 t1
left join table2 t2
on t1.Id = t2.t1Id and (t1.Status = 1 or t2.Id is not null)

现在,下面的查询匹配 2 个表并根据 ON 子句返回行,另外一个 WHERE 子句根据条件再次过滤行。

select * from 
table1 t1
left join table2 t2 on t1.Id = t2.t1Id 
where t1.Status = 1 or t2.Id is not null

在这里,尽管我们使用了 LEFT JOIN,但在这种情况下,它的作用类似于 INNER JOIN

所以,这里的两个查询产生不同的结果集。执行计划也不同,导致执行时间不同。

【讨论】:

我认为它不会产生不同的结果。无论是在表连接期间应用过滤器还是在它们连接后应用过滤器,结果都应该是相同的。【参考方案3】:

处理OR 的最佳方法是消除它(如果可能)或将其分解为更小的查询。把一个简短的查询分解成一个更长、更冗长的查询可能看起来并不优雅,但在处理OR 问题时,它通常是最好的选择:

select *
from table1 t1
     left join table2 t2 t1.Id = t2.t1Id 
where t1.Status = 1
union all
select *
from table1 t1
     left join table2 t2 t1.Id = t2.t1Id 
where t2.Id is not null

您可以在这篇文章中阅读更多内容: https://www.sqlshack.com/query-optimization-techniques-in-sql-server-tips-and-tricks/

【讨论】:

以上是关于MSSQL - 在 where 和 on 子句性能上添加条件的主要内容,如果未能解决你的问题,请参考以下文章

MSSQL WHERE YEAR 子句返回所有日期而不是指定日期[关闭]

连接的 WHERE 和 ON 之间的 SQL 区别 [重复]

使用 SSMS 在 where 子句中的每个 id 之前放置逗号

在 WHERE 子句中使用 REPLACE 检查拼写排列 - MS SQL

IF EXISTS 在 WHERE 子句中

PostgreSQL 中的 SQL JOIN - WHERE 子句中的执行计划与 ON 子句中的不同