ฉันคิดว่าฉันหมดความรู้ใน SQL Server ของฉันไปแล้ว ...
สำหรับการค้นหาช่องว่างในเซิร์ฟเวอร์ 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 ไม่มีทางที่จะเข้าร่วมหรือเปรียบเทียบสองชุดแยกกันตามลำดับของค่าใน set ... ดังนั้นการใช้ฟังก์ชั่น 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
(ซึ่งโดยวิธีฉันไม่รับประกันผลลัพธ์ - ดูเหมือนว่าจะทำงาน แต่ฉันคิดว่าพึ่งเริ่มที่อยู่ในลำดับในตารางงาน ... และมันช้าลง)
ใช้การเปลี่ยนแปลงผลรวม:
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 สำหรับการเปรียบเทียบเวลาเนื่องจากมันแสดงผลกับกริดต้องใช้เวลา ทดสอบกับ SQL 2012, VS2010, .net 4.0 Client Profile
ฉันจะชี้ให้เห็นว่าวิธีแก้ปัญหาทั้งสองทำงานคล้ายกันเรียงลำดับข้อมูลบนเซิร์ฟเวอร์ SQL ดังนั้นการโหลดเซิร์ฟเวอร์สำหรับการดึงข้อมูลเรียงจะคล้ายกันแล้วแต่วิธีที่คุณใช้ความแตกต่างเพียงอย่างเดียวคือการประมวลผลบนไคลเอนต์ (มากกว่าเซิร์ฟเวอร์) และการถ่ายโอนผ่านเครือข่าย
ฉันไม่ทราบว่าอาจแตกต่างกันอย่างไรเมื่อทำการแบ่งพาร์ติชันโดยพนักงานที่แตกต่างกันหรือบางทีคุณอาจต้องการข้อมูลเพิ่มเติมพร้อมข้อมูลช่องว่าง (แม้ว่าฉันจะไม่สามารถคิดอย่างอื่นนอกเหนือจาก id พนักงาน) หรือแน่นอนถ้า มีการเชื่อมต่อข้อมูลที่ช้าระหว่างเซิร์ฟเวอร์ SQL และเครื่องไคลเอนต์ (หรือไคลเอนต์ที่ช้า ) ... ฉันไม่ได้ทำการเปรียบเทียบการล็อคไทม์หรือการช่วงชิงปัญหาหรือปัญหา CPU / NETWORK สำหรับผู้ใช้หลายคน ... ดังนั้นฉัน ไม่ทราบว่ากรณีใดมีแนวโน้มที่จะเป็นคอขวดในกรณีนี้
สิ่งที่ฉันรู้คือใช่เซิร์ฟเวอร์ SQL ไม่ดีในการเปรียบเทียบชุดนี้และถ้าคุณไม่เขียนแบบสอบถามที่ถูกต้องคุณจะจ่ายมันอย่างสุดซึ้ง
ง่ายกว่าหรือยากกว่าการเขียน C # หรือไม่ ฉันไม่แน่ใจทั้งหมดการเปลี่ยนแปลง +/- 1 การรันโซลูชันทั้งหมดนั้นไม่ง่ายนัก แต่ฉันก็ไม่ใช่โซลูชันแรกที่บัณฑิตทั่วไปจะมา ... เมื่อทำเสร็จแล้วก็ง่ายพอที่จะคัดลอก แต่ ต้องใช้ความเข้าใจอย่างลึกซึ้งในการเขียนตั้งแต่แรก ... สามารถพูดได้เหมือนกันสำหรับเวอร์ชัน SQL ไหนยากกว่ากัน ข้อมูลอันไหนที่มีประสิทธิภาพมากกว่าในการโกงข้อมูล สิ่งใดมีศักยภาพมากขึ้นสำหรับการดำเนินการแบบขนาน เป็นเรื่องสำคัญหรือไม่เมื่อความแตกต่างนั้นเล็กมากเมื่อเทียบกับความพยายามในการเขียนโปรแกรม?
หนึ่งบันทึกล่าสุด; มีข้อ จำกัด ของข้อมูลที่ไม่ได้ระบุไว้ - StartedAt จะต้องน้อยกว่าFinishAt มิฉะนั้นคุณจะได้รับผลลัพธ์ที่ไม่ดี