Saya pikir saya telah kehabisan batas pengetahuan saya di SQL server yang satu ini ....
Untuk menemukan celah di SQL server (apa kode C # tidak), dan Anda tidak peduli memulai atau mengakhiri kesenjangan (yang sebelum mulai pertama, atau setelah selesai terakhir), maka kueri berikut (atau varian) adalah tercepat yang bisa saya temukan:
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
Yang bekerja dengan sedikit tangan untuk setiap set start-finish, Anda dapat memperlakukan start dan finish sebagai urutan yang terpisah, mengimbangi finish dengan satu dan celah ditampilkan.
mis. ambil (S1, F1), (S2, F2), (S3, F3), dan pesan sebagai: {S1, S2, S3, null} dan {null, F1, F2, F3} Kemudian bandingkan baris n ke baris n di setiap set, dan kesenjangan adalah di mana nilai set F kurang dari nilai set S ... masalahnya saya pikir adalah bahwa dalam SQL server tidak ada cara untuk bergabung atau membandingkan dua set terpisah murni pada urutan nilai-nilai di set ... maka penggunaan fungsi row_number untuk memungkinkan kita untuk menggabungkan berdasarkan murni pada nomor baris ... tetapi tidak ada cara untuk memberitahu SQL server bahwa nilai-nilai ini unik (tanpa memasukkannya ke dalam tabel var dengan indeks) di atasnya - yang membutuhkan waktu lebih lama - saya mencobanya), jadi saya pikir gabungan gabung kurang optimal? (Meskipun sulit untuk dibuktikan ketika itu lebih cepat daripada hal lain yang bisa saya lakukan)
Saya bisa mendapatkan solusi menggunakan fungsi 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
(yang omong-omong, saya tidak menjamin hasilnya - tampaknya berfungsi, tapi saya pikir mengandalkan BeginAt agar dalam urutan di tabel Tugas ... dan itu lebih lambat)
Menggunakan perubahan jumlah:
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
(tidak mengherankan, juga lebih lambat)
Saya bahkan mencoba fungsi agregat CLR (untuk mengganti jumlah - itu lebih lambat dari jumlah dan mengandalkan row_number () untuk menjaga urutan data), dan CLR fungsi tabel yang dihargai (untuk membuka dua set hasil dan membandingkan nilai berdasarkan murni pada urutan) ... dan itu juga lebih lambat. Saya membenturkan kepala saya berkali-kali pada SQL, dan keterbatasan CLR, mencoba banyak metode lain ...
Dan untuk apa?
Berjalan di mesin yang sama, dan meludahkan data C #, dan SQL memfilter data ke dalam file (sesuai kode C # asli), waktunya hampir sama .... kira-kira 2 detik untuk data 1 gap (C # biasanya lebih cepat ), 8-10 detik untuk set data multi-gap (SQL biasanya lebih cepat).
CATATAN : Jangan gunakan Lingkungan Pengembangan SQL Server untuk perbandingan waktu, karena tampilan ke grid membutuhkan waktu. Seperti yang diuji dengan profil klien SQL 2012, VS2010, .net 4.0
Saya akan menunjukkan bahwa kedua solusi melakukan cukup banyak pengurutan data yang sama pada server SQL sehingga beban server untuk fetch-sort akan serupa, solusi mana pun yang Anda gunakan, satu-satunya perbedaan adalah pemrosesan pada klien (bukan server) , dan transfer melalui jaringan.
Saya tidak tahu apa bedanya ketika dipartisi oleh anggota staf yang berbeda mungkin, atau ketika Anda mungkin membutuhkan data tambahan dengan informasi kesenjangan (meskipun saya tidak bisa memikirkan banyak hal selain id staf), atau tentu saja jika ada koneksi data yang lambat antara server SQL dan mesin klien (atau klien lambat ) ... Saya juga belum membuat perbandingan waktu-kunci, atau masalah pertikaian, atau masalah CPU / JARINGAN untuk banyak pengguna ... Jadi saya tidak tahu mana yang lebih mungkin menjadi hambatan dalam kasus ini.
Yang saya tahu, adalah ya, SQL server tidak pandai mengatur perbandingan ini, dan jika Anda tidak menulis kueri dengan benar, Anda akan membayar mahal.
Apakah lebih mudah atau lebih sulit daripada menulis versi C #? Saya tidak sepenuhnya yakin, Perubahan +/- 1, menjalankan solusi total tidak sepenuhnya intuitif juga, dan saya tetapi itu bukan solusi pertama lulusan rata-rata akan datang ke ... sekali selesai cukup mudah untuk menyalin, tetapi dibutuhkan wawasan untuk menulis di tempat pertama ... sama dapat dikatakan untuk versi SQL. Mana yang lebih sulit? Mana yang lebih kuat untuk data jahat? Mana yang lebih berpotensi untuk operasi paralel? Apakah penting ketika perbedaannya sangat kecil dibandingkan dengan upaya pemrograman?
Satu not terakhir; ada batasan yang tidak disebutkan pada data - StartingAt harus lebih kecil dari FinishedAt, atau Anda akan mendapatkan hasil yang buruk.