Я думаю, що я вичерпав межі своїх знань на SQL сервері на цьому ...
Для пошуку розриву в SQL-сервері (що робить код C #), і вам не байдуже починати чи закінчувати прогалини (ті, які були перед першим запуском або після останнього завершення), то наступний запит (або варіанти) - це найшвидший, який я міг знайти:
SELECT e.FinishedAt as GapStart, s.StartedAt as GapEnd
FROM
(
SELECT StartedAt, ROW_NUMBER() OVER (ORDER BY StartedAt) AS rn
FROM dbo.Tasks
) AS s
INNER JOIN
(
SELECT FinishedAt, ROW_NUMBER() OVER (ORDER BY FinishedAt) + 1 AS rn
FROM dbo.Tasks
) AS e ON e.rn = s.rn and s.StartedAt > e.FinishedAt
Що працює, хоч і незначно, що для кожного набору стартових фінішів ви можете ставитись до старту та фінішу як до окремих послідовностей, зсув фінішу на один і пропуски показані.
наприклад, взяти (S1, F1), (S2, F2), (S3, F3) і замовити так: {S1, S2, S3, null} і {null, F1, F2, F3} Потім порівняти рядок n з рядком n у кожному наборі, і прогалини там, де задане значення F менше, ніж встановлене значення S ... проблема, я думаю, що на SQL-сервері немає способу з'єднати або порівняти два окремих набори суто за порядком значень у набір ... отже, використання функції row_number дозволяє дозволити нас об'єднати лише на основі рядка номер ... але немає можливості сказати SQL-серверу, що ці значення унікальні (без вставлення їх у таблицю var з індексом на це - що займає більше часу - я спробував це), тому я думаю, що об'єднання об'єднань є менш оптимальним? (хоча важко довести, коли це швидше за все, що я міг би зробити)
Мені вдалося отримати рішення за допомогою функцій LAG / LEAD:
select * from
(
SELECT top (100) percent StartedAt, FinishedAt, LEAD(StartedAt, 1, null) OVER (Order by FinishedAt) as NextStart
FROM dbo.Tasks
) as x
where NextStart > FinishedAt
(що, до речі, результати не гарантую - це, здається, працює, але я думаю, що покладається на те, щоб StartedAt був у порядку в таблиці завдань ... і це було повільніше)
Використання зміни суми:
select * from
(
SELECT EventTime, Change, SUM(Change) OVER (ORDER BY EventTime, Change desc ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as RunTotal --, x.*
FROM
(
SELECT StartedAt AS EventTime, 1 AS Change
FROM dbo.Tasks
UNION ALL
SELECT FinishedAt AS EventTime, -1 AS Change
FROM dbo.Tasks
) AS TaskEvents
) as x
where x.RunTotal = 0 or (x.RunTotal = 1 and x.Change = 1)
ORDER BY EventTime, Change DESC
(не дивно, також повільніше)
Я навіть спробував функцію сукупності CLR (щоб замінити суму - це було повільніше, ніж сума, і покладався на row_number () для збереження порядку даних), і CLR - табличну функцію (щоб відкрити два набори результатів і порівняти значення на основі чисто по послідовності) ... і це теж було повільніше. Я стільки разів стукав головою про обмеження SQL та CLR, намагаючись багато інших методів ...
А для чого?
Працюючи на одній машині та плюючи і дані C #, і SQL відфільтровані дані у файл (відповідно до оригінального коду C #), часи практично однакові .... приблизно 2 секунди для даних 1 проміжку (C # зазвичай швидше ), 8-10 секунд для множинного набору даних (SQL зазвичай швидше).
ПРИМІТКА . Не використовуйте середовище розробки SQL Server для порівняння часу, оскільки його відображення до сітки вимагає часу. Як перевірено на SQL 2012, VS2010, .net 4.0 Профіль клієнта
Я зазначу, що обидва рішення виконують майже однакове сортування даних на SQL-сервері, тому завантаження сервера для вибору сортування буде подібним, яке б рішення ви не використовували, різницею є лише обробка на клієнті (а не на сервері) , і передачу по мережі.
Я не знаю, яка різниця може бути при розподілі на різних співробітників, або коли вам можуть знадобитися додаткові дані з інформацією про розрив (хоча я не можу придумати більше іншого, крім ідентифікатора персоналу), або, звичайно, якщо існує повільне з'єднання даних між сервером SQL та клієнтською машиною (або повільним клієнтом) ... Я також не порівнював час блокування, або проблеми з суперечками, або проблеми з процесором / мережею для декількох користувачів ... Тож я не знаю, який з них, швидше за все, буде вузьким місцем у цьому випадку.
Що я знаю, так, так, SQL-сервер не дуже хороший у подібних порівняннях, і якщо ви не пишете запит правильно, ви заплатите за нього дорого.
Це легше чи складніше, ніж писати версію C #? Я не зовсім впевнений, що зміна +/- 1, що працює з тотальним рішенням, теж не зовсім інтуїтивно зрозуміла, і я, але це не перше рішення, до якого прийшов би середній випускник ... як тільки це зробити, це досить просто скопіювати, але писати потрібно в першу чергу ... те ж саме можна сказати і для версії SQL. Що складніше? Що є більш надійним для неправдивих даних? Який має більше потенціалу для паралельних операцій? Чи справді важливо, коли різниця настільки мала в порівнянні з програмуванням?
Остання остання нота; є нестабільне обмеження в даних - StartedAt повинен бути меншим, ніж FinishedAt, інакше ви отримаєте погані результати.