結合とウィンドウ関数を使用してリード値とラグ値を取得するパフォーマンスの比較


11

私は20Mの行のテーブルを有し、各行は3つの列を有している:timeid、およびvalue。それぞれについてidtime、そこにあるvalue状態のため。time特定の特定の特定のリードとラグの値を知りたいid

これを達成するために2つの方法を使用しました。1つの方法は結合を使用し、もう1つの方法は、クラスター化インデックスがオンtimeおよびのウィンドウ関数lead / lagを使用することidです。

これら2つの方法のパフォーマンスを実行時間で比較しました。結合メソッドは16.3秒かかり、ウィンドウ関数メソッドは20秒かかります(インデックスの作成時間は含まれません)。結合メソッドがブルートフォースであるときにウィンドウ関数が進んでいるように見えるので、これは私を驚かせました。

2つのメソッドのコードは次のとおりです。

インデックスを作成

create clustered index id_time
 on tab1 (id,time)

結合方法

select a1.id,a1.time
   a1.value as value, 
   b1.value as value_lag,
   c1.value as value_lead
into tab2
from tab1 a1
left join tab1 b1
on a1.id = b1.id
and a1.time-1= b1.time
left join tab1 c1
on a1.id = c1.id
and a1.time+1 = c1.time

を使用して生成されたIO統計SET STATISTICS TIME, IO ON

結合方法の統計

これがjoinメソッドの実行計画です

ウィンドウ関数法

select id, time, value, 
   lag(value,1) over(partition by id order by id,time) as value_lag,
   lead(value,1) over(partition by id order by id,time) as value_lead
into tab2
from tab1

time0.5秒節約するだけで注文できます。)

ウィンドウ関数メソッドの実行計画はこちら

IO統計

[ウィンドウ関数法4の統計]


私は、内のデータをチェックしsample_orig_month_1999、生のデータが十分で注文しているようだidtime。これがパフォーマンスの違いの理由ですか?

結合メソッドはウィンドウ関数メソッドよりも論理的な読み取りが多いようですが、前者の実行時間は実際には短くなっています。前者の方が並列処理が優れているからですか?

簡潔なコードのため、ウィンドウ関数メソッドが好きですが、この特定の問題に対してスピードを上げる方法はありますか?

Windows 10 64ビットでSQL Server 2016を使用しています。

回答:


11

自己結合と比較して、LEADおよびLAGウィンドウ関数の行モードパフォーマンスが比較的低いことは、新しいことではありません。たとえば、Michael Zilberstein 2012年にSQLblog.comでそれについて書いています。(繰り返される)セグメント、シーケンスプロジェクト、ウィンドウスプール、およびストリーム集約プランのオペレーターには、かなりのオーバーヘッドがあります。

企画部

SQL Server 2016には、ウィンドウアグリゲートのバッチモード処理を有効にするという新しいオプションがあります。これには、たとえ空であっても、テーブルに何らかの列ストアインデックスが必要です。列ストアインデックスの存在は、オプティマイザがバッチモードプランを検討するために現在必要です。特に、これにより、はるかに効率的なWindow Aggregateバッチモードオペレーターが可能になります。

これをテストするには、空の非クラスター化列ストアインデックスを作成します。

 -- Empty CS index
CREATE NONCLUSTERED COLUMNSTORE INDEX dummy 
ON dbo.tab1 (id, [time], [value]) 
WHERE id < 0 AND id > 0;

クエリ:

SELECT
    T1.id,
    T1.[time],
    T1.[value],
    value_lag = 
        LAG(T1.[value]) OVER (
            PARTITION BY T1.id
            ORDER BY T1.[time]),
    value_lead =
        LEAD(T1.[value]) OVER (
            PARTITION BY T1.id
            ORDER BY T1.[time])
FROM dbo.tab1 AS T1;

これで次のような実行計画が表示されます。

バッチモードの行ストアプラン

...はるかに速く実行される可能性があります。

OPTION (MAXDOP 1)結果を新しいテーブルに格納するときに、同じプラン形状を取得するために、または他のヒントを使用する必要がある場合があります。プランの並列バージョンでは、バッチモードでのソート(またはおそらく2つ)が必要ですが、少し遅くなる可能性があります。それはむしろあなたのハードウェアに依存します。

Batch Mode Window Aggregateオペレーターの詳細については、Itzik Ben-Ganによる以下の記事を参照してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.