Tôi nghĩ rằng tôi đã sử dụng hết giới hạn kiến thức của mình trong máy chủ SQL trên cái này ....
Để tìm khoảng trống trong máy chủ SQL (mã C # làm gì) và bạn không quan tâm đến việc bắt đầu hoặc kết thúc các khoảng trống (những khoảng trống trước khi bắt đầu đầu tiên hoặc sau khi kết thúc cuối cùng), thì truy vấn sau (hoặc các biến thể) là nhanh nhất tôi có thể tìm thấy:
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
Điều này có hiệu quả mặc dù đối với mỗi bộ bắt đầu-kết thúc, bạn có thể coi bắt đầu và kết thúc là các chuỗi riêng biệt, bù lại kết thúc bằng một và các khoảng trống được hiển thị.
ví dụ: lấy (S1, F1), (S2, F2), (S3, F3) và sắp xếp theo thứ tự: {S1, S2, S3, null} và {null, F1, F2, F3} Sau đó so sánh hàng n với hàng n trong mỗi bộ và các khoảng trống là nơi giá trị bộ F nhỏ hơn giá trị bộ S ... vấn đề tôi nghĩ là trong máy chủ SQL không có cách nào để nối hoặc so sánh hai bộ riêng biệt hoàn toàn theo thứ tự của các giá trị trong tập hợp ... do đó việc sử dụng hàm row_number để cho phép chúng ta hợp nhất hoàn toàn dựa trên số hàng ... nhưng không có cách nào để nói với máy chủ SQL rằng các giá trị này là duy nhất (không chèn chúng vào var bảng với chỉ mục trên đó - mất nhiều thời gian hơn - tôi đã thử nó), vì vậy tôi nghĩ rằng kết hợp hợp nhất là ít hơn tối ưu? (mặc dù khó chứng minh khi nó nhanh hơn bất kỳ điều gì khác tôi có thể làm)
Tôi đã có thể nhận được các giải pháp bằng cách sử dụng các hàm 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
(bằng cách này, tôi không đảm bảo kết quả - có vẻ như nó hoạt động, nhưng tôi nghĩ dựa vào StartedAt theo thứ tự trong bảng Nhiệm vụ ... và nó chậm hơn)
Sử dụng thay đổi tổng:
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
(không có gì bất ngờ, cũng chậm hơn)
Tôi thậm chí đã thử một hàm tổng hợp CLR (để thay thế tổng - nó chậm hơn tổng và dựa vào row_number () để giữ thứ tự của dữ liệu) và CLR một hàm có giá trị bảng (để mở hai tập kết quả và so sánh hoàn toàn các giá trị theo trình tự) ... và nó cũng chậm hơn. Tôi đã đập đầu rất nhiều lần vào SQL và các hạn chế CLR, thử nhiều phương pháp khác ...
Và để làm gì?
Chạy trên cùng một máy và nhổ cả dữ liệu C # và dữ liệu đã lọc SQL vào một tệp (theo mã C # gốc), thời gian gần như giống nhau .... khoảng 2 giây cho dữ liệu 1 khoảng cách (C # thường nhanh hơn ), 8-10 giây cho tập dữ liệu nhiều khoảng cách (SQL thường nhanh hơn).
LƯU Ý : Không sử dụng Môi trường phát triển máy chủ SQL để so sánh thời gian, vì việc hiển thị trên lưới sẽ mất thời gian. Như đã thử nghiệm với SQL 2012, VS2010, .net 4.0 Cấu hình máy khách
Tôi sẽ chỉ ra rằng cả hai giải pháp thực hiện khá nhiều cách sắp xếp dữ liệu giống nhau trên máy chủ SQL để tải máy chủ cho fetch-sort sẽ tương tự nhau, cho dù bạn sử dụng giải pháp nào, sự khác biệt duy nhất là xử lý trên máy khách (chứ không phải máy chủ) và chuyển qua mạng.
Tôi không biết sự khác biệt có thể là gì khi phân vùng bởi các nhân viên khác nhau, hoặc khi bạn có thể cần thêm dữ liệu với thông tin về khoảng trống (mặc dù tôi không thể nghĩ gì khác ngoài id nhân viên), hoặc tất nhiên nếu có một kết nối dữ liệu chậm giữa máy chủ SQL và máy khách (hoặc máy khách chậm ) ... Tôi cũng chưa thực hiện so sánh các vấn đề về thời gian khóa hoặc tranh chấp hoặc các vấn đề CPU / NETWORK cho nhiều người dùng ... Vì vậy, tôi không biết cái nào có nhiều khả năng là nút cổ chai trong trường hợp này.
Những gì tôi biết, là có, máy chủ SQL không tốt trong loại so sánh được đặt này và nếu bạn không viết đúng truy vấn, bạn sẽ phải trả giá đắt cho nó.
Nó dễ hơn hay khó hơn viết phiên bản C #? Tôi không hoàn toàn chắc chắn, Thay đổi +/- 1, chạy giải pháp tổng thể cũng không hoàn toàn trực quan, và tôi nhưng đó không phải là giải pháp đầu tiên mà một sinh viên tốt nghiệp trung bình sẽ đến ... một khi thực hiện nó đủ dễ để sao chép, nhưng cần có cái nhìn sâu sắc để viết ở vị trí đầu tiên ... có thể nói tương tự cho phiên bản SQL. Cái nào khó hơn? Cái nào mạnh hơn để lừa đảo dữ liệu? Cái nào có nhiều tiềm năng cho các hoạt động song song? Có thực sự quan trọng khi sự khác biệt quá nhỏ so với nỗ lực lập trình?
Một lưu ý cuối cùng; có một ràng buộc không có căn cứ đối với dữ liệu - StartedAt phải nhỏ hơn DoneAt , nếu không bạn sẽ nhận được kết quả xấu.