为什么IsNull与coalesce(同一个查询)的速度慢两倍?

时间:2011-05-27 13:00:05

标签: performance sql-server-2008 isnull

我们在SQL Server 2008(SP1)上遇到了一个奇怪的情况 - 10.0.2531.0(X64) - Win2008 SP2(X64)。

这是一个重问题:

select t1.id, t2.id 
from t1, t2
where 
     t1.id = t2.ext_id
     and isnull(t1.vchCol1, 'Null') = isnull(t2.vchCol1, 'Null')
     and isnull(t1.vchCol2, 'Null') = isnull(t2.vchCol2, 'Null')
     .... and about 10 more comparisons with Isnull

UPD :比较的所有列(ID除外)均为varchar(~30 ... 200)
T1为~130mln行,T2为~300k行。

这些查询在相当大的Dev服务器上运行 ~5小时 - 这很慢,但我们能做什么?

虽然我们调查了可能的优化方法 - 我们发现,在上面的查询中将“isnull”更改为“coalesce”可以获得双倍的性能提升 - 并且查询现在可以运行 ~2小时

UPD :当我们删除所有ISNULL项检查并仅使用t1.vchCol1 = t2.vchCol1后,查询将在 40mins 之后完成。

问题是:这是否已知行为,我们应该避免在任何地方使用 IsNull

4 个答案:

答案 0 :(得分:10)

我想知道你是否通过明确地将案件分开来看到改进:

...
AND ((t1.vchCol1 = t2.vchCol1) OR (t1.vchCol1 IS NULL AND t2.vchCol1 IS NULL))
AND ((t1.vchCol2 = t2.vchCol2) OR (t1.vchCol2 IS NULL AND t2.vchCol2 IS NULL))
...

答案 1 :(得分:3)

你在这个问题上找到的大多数文章似乎与此相矛盾。 ISNULL(略微)比COALESCE快。{/ p>

Differences between ISNULL and COALESCE

  

COALESCE基本上翻译为CASE   表达式ISNULL是内置的   在数据库引擎中实现   ...
  这将成为一种表现   与COALESCE的差异和查询   这里的情况往往更糟。

ISNULL vs. COALESCE

  

我在a上多次运行这些测试   几个不同的服务器,ISNULL   似乎非常一致   超出COALESCE平均值   10%或12%。但那就是   6秒和5.3之间的差异   秒(近似平均值   我的服务器上每次测试的运行时间)   一百万次执行的过程。   非常值得的功能和   标准合规牺牲,在   至少在我使用这些场景的场景中   。的功能。

COALESCE vs ISNULL vs IS NULL OR

  

表现最好的是IS NULL OR案例,   而所有3个之间的区别   他们很小。

答案 2 :(得分:2)

您可能需要考虑将计算列添加到包含校验和值的每个表中。然后,在ID列和校验和值上创建索引,最后使用连接中的校验和值。像这样:

Alter Table T1 Add CheckSumId As CHECKSUM(vchCol1, vchCol2, vchCol3)
Alter Table T2 Add CheckSumId As CHECKSUM(vchCol1, vchCol2, vchCol3)

Create NonClustered index idx_T1_Checksum On T1(id, CheckSumId)
Create NonClustered index idx_T2_Checksum On T2(ext_id, CheckSumId)

然后你的查询将变成......

select t1.id, t2.id 
from t1 Inner Join t2
       On t1.id = t2.ext_id
       And T1.CheckSumId = T2.CheckSumId
where  isnull(t1.vchCol1, 'Null') = isnull(t2.vchCol1, 'Null')
     and isnull(t1.vchCol2, 'Null') = isnull(t2.vchCol2, 'Null')

当然,这将使用额外的索引空间,但它只是2个整数,应该非常有效。每次插入,更新和删除都会有性能损失,因为需要维护另一个索引。但是,我怀疑这会对性能产生很大影响。

答案 3 :(得分:1)

我意识到这是一年之后,但是......

对于这种逐列比较,您可以考虑使用EXCEPT。此外,EXCEPT将NULL视为另一个值,而不是“它可能是任何东西!”,因为我喜欢称之为。

“比较行以确定不同的值时,两个NULL值被视为相等。” - 来自http://msdn.microsoft.com/en-us/library/ms188055.aspx