Performance 为什么IsNull的速度是coalesce(相同查询)的两倍?
我们在SQLServer2008(SP1)-10.0.2531.0(X64)-Win2008SP2(X64)上遇到了一个奇怪的情况 这里有一个很难回答的问题:Performance 为什么IsNull的速度是coalesce(相同查询)的两倍?,performance,sql-server-2008,isnull,Performance,Sql Server 2008,Isnull,我们在SQLServer2008(SP1)-10.0.2531.0(X64)-Win2008SP2(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') = isnu
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
时,查询在40分钟后完成
问题是:这是已知的行为吗?我们应该避免在任何地方使用IsNull吗?关于这个主题的大多数文章似乎都与此相矛盾
ISNULL
比COALESCE
快一点
合并
基本上转化为案例
表达式和ISNULL
是内置的
在数据库引擎中实现。…
这将是一场表演 与
合并的差异和查询
这里的情况往往更糟
我在一台计算机上运行了几次这些测试
几乎没有不同的服务器,ISNULL
看起来相当一致
平均执行合并
10%或12%。但这就是问题所在
6秒和5.3秒之间的差值
秒(近似平均值)
每个测试在我的服务器上的运行时间),超过
一百万次处决的过程。
几乎不值得拥有这些功能和功能
标准符合性牺牲,在
至少在我使用的场景中
功能
最好的执行者是为空或
大小写,
而这三者之间的差异
它们是次要的
我想知道您是否会通过明确地将案例拆分出来看到改进:
...
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))
...
您可能想考虑在包含校验和值的每个表中添加一个计算列。然后,在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个整数,这应该是非常有效的。由于需要维护另一个索引,因此每次插入、更新和删除都会有性能损失。但是,我怀疑这会对性能产生很大影响。我意识到这是一年后的事,但是
对于这种按列比较,您可以考虑使用除此之外的。另外,EXCEPT将NULL视为另一个值,而不是我喜欢称之为“它可以是任何东西!”
在比较行以确定不同的值时,两个空值被视为相等
--从什么数据类型是vchCol1等?我认为
(t1.vchCol1=t2.vchCol1)
比运行函数(喜欢强制表扫描)在性能上更好,但它需要将ANSI_NULLS
设置为关闭
。你看过查询执行计划了吗?我肯定你对此无能为力,但这只是空值是邪恶的另一个原因@zmische-你找到了两者之间差异的根本原因了吗?但在我们的案例中,在切换到凝聚后,我们得到了从5小时到2小时的提升。原因是什么?对于我来说-ISNULL应该更快,这就是为什么我如此困惑的原因。只需添加,在ISNULL(子查询,X)
或COALESCE(子查询,X)
的情况下,第二个会对子查询求值两次。同意。这种模式。在查看链接答案时(与参数相比与另一列略有不同),我发现它在计划中只是一个简单的等式。因此您认为这是正常行为,coalesce
比Isnull
快2倍。我们所能做的就是拆分案例,以便SQL清楚地了解如何进行优化?因此,不应将其视为SQL Server中的性能缺陷?@zmische-我会认为coalesce
和isnull
表达式都是无法组织且不理想的。不知道为什么您会看到两者在性能上的差异。计划有什么不同?其中一个是否比另一个具有更精确的行估计?哈希联接中表的顺序相同还是相反?关于逻辑读取和CPU时间,将统计信息IO设置为ON
和将统计时间设置为ON
说明了什么?可能在ISNULL
版本中,由于估计值不同,menory授权不足以进行散列联接。@Martin-thx用于提问。我没有确切的统计数据-另一个团队正在使用该服务器。但我会在下一次运行中尝试解决这个问题。@zmische-我认为内存不足和散列溢出是很可能的。您应该能够从估计的计划中看到这一点,而不需要通过查看估计的行数和行大小来运行整个查询。