SQL Server: упаковываем интервалы с приоритетами. Шаг 4 и оптимизация решения с использованием APPLY. Продолжение
Затем можно использовать следующий запрос, чтобы применить функцию к каждому пользователю:
SELECT U.username, S.pty, S.starttime, S.endtime
FROM dbo.Users AS U
CROSS APPLY dbo.PackedIntervals(U.username) AS S
OPTION(QUERYTRACEON 8649);Обратите внимание, что на моем ноутбуке без флага трассировки 8649 SQL Server создает последовательный план, выполнение которого занимает всего 15 секунд. Это лишь третья часть времени выполнения первоначального решения и уже очень высокая скорость. Метод APPLY лучше работает при параллелизации, поэтому для демонстрационных целей я применил параллельный план с флагом трассировки. После параллелизации запрос был выполнен за 8 секунд с планом, показанным на рисунке выше.
В определенных условиях решение может возвращать вырожденные интервалы (где starttime = endtime). Они не имеют смысла, когда интервал закрыто-открытый, как в нашем примере. Чтобы избавиться от них, достаточно добавить к самому внешнему сгруппированному запросу следующий фильтр HAVING непосредственно после предложения GROUP BY:
HAVING MAX (ts) > MIN (ts) Соответствующий пример можно увидеть, если использовать следующие тестовые данные:
TRUNCATE TABLE dbo.Sessions;
TRUNCATE TABLE dbo.Users;
INSERT INTO dbo.Users(username) VALUES('UseiT);
INSERT INTO dbo.sessions(username, starttime, endtime, pty) VALUES
('UserV, '2015-01-01', '2015-01-05', 3),
('UserT, '2015-01-02', '2015-01-03', 1),
('Userl', '2015-01-03', '2015-01-04', 2); Если выполнить код решения («Полное решение»), приведенный выше, то одной из выходных строк будет этот вырожденный интервал:
Добавьте приведенное выше предложение HAVING к внешнему запросу:
SELECT username, newpty AS pty, MIN (ts) AS starttime, MAX (ts) AS endtime FROM C4
GROUP BY username, newpty, grp HAVING MAX (ts) > MIN (ts);
Итак, мы рассмотрели вариант классической задачи упаковывания интервалов, где интервалы наделены приоритетами, и в случаях перекрывания предполагается, что будет возвращен сегмент с самым высоким приоритетом. В использованном мною решении широко применяются оконные функции, в том числе для вычисления номеров строк и нарастающих итогов. Для обработки приоритетов используется двоичное представление приоритетов. Наконец, с помощью метода CROSS APPLY Адама Маханика я дополнительно усовершенствовал решение, разделив одну большую масштабируемую задачу на несколько более мелких задач.