5

SQL Server 2008 (SP1) - 10.0.2531.0 (X64) - Win2008 SP2 (X64) で奇妙な状況に遭遇しました。

これは、1 つの重いクエリです。

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 倍になることがわかりました。クエリは現在、約 2 時間実行されています。

UPD : すべてのISNULLチェックを削除しt1.vchCol1 = t2.vchCol1てクエリのみを使用すると、40 分後に終了します

質問: これは既知の動作であり、どこでもIsNullを使用しないようにする必要がありますか?

4

4 に答える 4

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))
...
于 2011-05-27T13:11:17.647 に答える
3

このテーマに関する記事のほとんどは、これと矛盾しているようです。ISNULLは(わずかに)より高速ですCOALESCE

ISNULLとの違いCOALESCE

COALESCE基本的にはCASE 式に変換ISNULLされ、データベースエンジンに組み込まれています。
...
これにより、パフォーマンスに違いが生じ、クエリがCOALESCE 悪化することがよくあります。

ISNULL対。COALESCE

私はこれらのテストをいくつかの異なるサーバーで数回ISNULL 実行COALESCEしましたが、平均して10%または12%優れているように見えます。しかし、これは6秒と5.3秒(私のサーバーでのテストあたりのおおよその平均実行時間)の差であり、100万回の実行の過程で発生します。少なくとも私がこれらの機能を使用するシナリオでは、機能と標準への準拠を犠牲にする価値はほとんどありません。

COALESCEISNULLIS NULL OR

最高のパフォーマンスを発揮するのはIS NULL ORケースですが、3つすべての違いはわずかです。

于 2011-05-27T13:04:11.760 に答える
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 つの整数です。また、別のインデックスを維持する必要があるため、挿入、更新、および削除ごとにパフォーマンスが低下します。ただし、これはパフォーマンスに大きな影響を与えると思います。

于 2011-05-27T14:51:23.830 に答える
1

気付けば1年後ですが…

このような列ごとの比較では、EXCEPT の使用を検討してください。また、EXCEPT は NULL を、私が好きなように「何でもかまいません!」ではなく、別の値のように扱います。

「個別の値を決定するために行を比較する場合、2 つの NULL 値は等しいと見なされます。」-- http://msdn.microsoft.com/en-us/library/ms188055.aspxより

于 2012-01-26T23:45:47.470 に答える