Mam tabeli z wierszy 20m, a każdy wiersz ma 3 kolumny: time
, id
, i value
. Dla każdego id
i time
istnieje value
status. Chcę poznać wartości wyprzedzenia i opóźnienia określonego time
dla określonego id
.
Użyłem dwóch metod, aby to osiągnąć. Jedną z metod jest łączenie, a drugą - funkcja okna lead / lag z indeksem klastrowym time
i id
.
Porównałem wydajność tych dwóch metod według czasu wykonania. Metoda łączenia zajmuje 16,3 sekundy, a metoda funkcji okna zajmuje 20 sekund, nie licząc czasu na utworzenie indeksu. Zaskoczyło mnie to, ponieważ funkcja okna wydaje się być zaawansowana, podczas gdy metody łączenia są brutalne.
Oto kod dwóch metod:
Utwórz indeks
create clustered index id_time
on tab1 (id,time)
Metoda łączenia
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
Statystyki IO generowane przy użyciu SET STATISTICS TIME, IO ON
:
Oto plan wykonania metody łączenia
Metoda funkcji okna
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
(Zamawianie tylko time
oszczędza 0,5 sekundy.)
Oto plan wykonania dla metody funkcji Windows
Statystyka IO
[
Sprawdziłem dane sample_orig_month_1999
i wydaje się, że nieprzetworzone dane są dobrze uporządkowane przez id
i time
. Czy to jest przyczyną różnicy wydajności?
Wydaje się, że metoda łączenia ma więcej logicznych odczytów niż metoda funkcji okna, podczas gdy czas wykonania dla pierwszej jest w rzeczywistości krótszy. Czy dlatego, że ten pierwszy ma lepszą równoległość?
Podoba mi się metoda funkcji okna ze względu na zwięzły kod, czy jest jakiś sposób na przyspieszenie tego konkretnego problemu?
Używam SQL Server 2016 na 64-bitowym systemie Windows 10.