У меня есть таблица с 20М строк, а каждая строка имеет 3 колонки: time
, id
, и value
. Для каждого id
и time
есть value
статус. Я хочу знать опережающие и запаздывающие значения определенного time
для конкретного id
.
Я использовал два метода для достижения этой цели. Один метод использует соединение, а другой - использование опережающих / запаздывающих оконных функций с кластеризованным индексом time
и id
.
Я сравнил производительность этих двух методов по времени выполнения. Метод объединения занимает 16,3 секунды, а метод оконной функции - 20 секунд, не считая времени на создание индекса. Это удивило меня, потому что оконная функция кажется продвинутой, в то время как методы соединения - грубая сила.
Вот код для двух методов:
Создать индекс
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
:
Вот план выполнения для метода соединения
Метод оконной функции
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 секунды.)
Вот план выполнения для метода оконной функции
Статистика IO
[
Я проверил данные, sample_orig_month_1999
и кажется, что исходные данные хорошо упорядочены по id
и time
. Это причина разницы в производительности?
Кажется, что метод соединения имеет больше логических чтений, чем метод оконной функции, в то время как время выполнения для первого фактически меньше. Это потому, что у первого лучше параллелизм?
Мне нравится метод оконной функции из-за лаконичного кода, есть ли способ ускорить его для этой конкретной проблемы?
Я использую SQL Server 2016 в Windows 10 64 бит.