2,000万行のテーブルがあり、各行にはtime
、id
、value
の3つの列があります。 id
およびtime
ごとに、ステータスのvalue
があります。特定のtime
に対する特定のid
のリード値とラグ値を知りたい。
これを達成するために2つの方法を使用しました。 1つの方法は結合を使用し、もう1つの方法はtime
およびid
のクラスター化インデックスを使用したウィンドウ関数lead/lagを使用することです。
これら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
SET STATISTICS TIME, IO ON
を使用して生成されたIO統計:
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
(time
のみで注文すると、0.5秒節約できます。)
Window function method の実行計画は次のとおりです。
IO統計
[
sample_orig_month_1999
のデータを確認したところ、生データはid
とtime
の順に並べられているようです。これがパフォーマンスの違いの理由ですか?
結合メソッドはウィンドウ関数メソッドよりも論理的な読み取りが多いようですが、前者の実行時間は実際には短くなっています。前者の方が並列処理が優れているからでしょうか。
簡潔なコードのため、ウィンドウ関数メソッドが好きですが、この特定の問題に対してそれを高速化する方法はありますか?
Windows 10 64ビットでSQL Server 2016を使用しています。
自己結合と比較して、LEAD
およびLAG
ウィンドウ関数の行モードパフォーマンスが比較的低いことは、目新しいことではありません。たとえば、Michael Zilberstein それについて書いた はSQLblog.comで2012年にさかのぼります。
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による以下の記事を参照してください。