यह क्वेरी काम भी करती है। इसका प्रदर्शन बहुत अच्छा है (जबकि निष्पादन योजना इतनी शानदार नहीं दिखती है, वास्तविक CPU और IO कई अन्य प्रश्नों को मात देते हैं)।
इसे Sql Fiddle में काम करते हुए देखें ।
WITH Times AS (
SELECT DISTINCT
H.WorkerID,
T.Boundary
FROM
dbo.JobHistory H
CROSS APPLY (VALUES (H.JobStart), (H.JobEnd)) T (Boundary)
), Groups AS (
SELECT
WorkerID,
T.Boundary,
Grp = Row_Number() OVER (PARTITION BY T.WorkerID ORDER BY T.Boundary) / 2
FROM
Times T
CROSS JOIN (VALUES (1), (1)) X (Dup)
), Boundaries AS (
SELECT
G.WorkerID,
TimeStart = Min(Boundary),
TimeEnd = Max(Boundary)
FROM
Groups G
GROUP BY
G.WorkerID,
G.Grp
HAVING
Count(*) = 2
)
SELECT
B.WorkerID,
WorkedMinutes = Sum(DateDiff(minute, 0, B.TimeEnd - B.TimeStart))
FROM
Boundaries B
WHERE
EXISTS (
SELECT *
FROM dbo.JobHistory H
WHERE
B.WorkerID = H.WorkerID
AND B.TimeStart < H.JobEnd
AND B.TimeEnd > H.JobStart
)
GROUP BY
WorkerID
;
WorkerID, JobStart, JobEnd, JobID
. पर क्लस्टर्ड इंडेक्स के साथ , और ऊपर से 7 पंक्तियों के नमूने के साथ, नए कार्यकर्ता/नौकरी डेटा के लिए एक टेम्पलेट को 14,336 पंक्तियों वाली तालिका उत्पन्न करने के लिए पर्याप्त बार दोहराया गया, यहां प्रदर्शन परिणाम दिए गए हैं। मैंने पृष्ठ पर अन्य कार्यशील/सही उत्तरों को शामिल किया है (अब तक):
Author CPU Elapsed Reads Scans
------ --- ------- ------ -----
Erik 157 166 122 2
Gordon 375 378 106964 53251
मैंने एक अलग (धीमे) सर्वर से अधिक विस्तृत परीक्षण किया (जहां प्रत्येक क्वेरी को 25 बार चलाया गया था, प्रत्येक मीट्रिक के लिए सर्वोत्तम और सबसे खराब मान फेंक दिए गए थे, और शेष 23 मान औसत थे) और निम्न प्राप्त किया:
Query CPU Duration Reads Notes
-------- ---- -------- ------ ----------------------------------
Erik 1 215 231 122 query as above
Erik 2 326 379 116 alternate technique with no EXISTS
Gordon 1 578 682 106847 from j
Gordon 2 584 673 106847 from dbo.JobHistory
मैंने सोचा कि वैकल्पिक तकनीक से चीजों में सुधार होगा। खैर, इसने 6 रीड्स को बचाया, लेकिन बहुत अधिक CPU (जो समझ में आता है) की लागत है। प्रत्येक टाइमलाइस के प्रारंभ/समाप्ति के आंकड़ों को अंत तक ले जाने के बजाय, यह केवल पुनर्गणना करना सबसे अच्छा है कि EXISTS
के साथ कौन से स्लाइस रखना है मूल डेटा के खिलाफ। यह हो सकता है कि कई नौकरियों वाले कुछ श्रमिकों की एक अलग प्रोफ़ाइल विभिन्न प्रश्नों के प्रदर्शन आंकड़े बदल सकती है।
यदि कोई इसे आजमाना चाहता है, तो CREATE TABLE
का उपयोग करें और INSERT
मेरे बेला से बयान और फिर इसे 11 बार चलाएँ:
INSERT dbo.JobHistory
SELECT
H.JobID + A.MaxJobID,
H.WorkerID + A.WorkerCount,
DateAdd(minute, Elapsed + 45, JobStart),
DateAdd(minute, Elapsed + 45, JobEnd)
FROM
dbo.JobHistory H
CROSS JOIN (
SELECT
MaxJobID = Max(JobID),
WorkerCount = Max(WorkerID) - Min(WorkerID) + 1,
Elapsed = DateDiff(minute, Min(JobStart), Min(JobEnd))
FROM dbo.JobHistory
) A
;
मैंने इस प्रश्न के लिए दो अन्य समाधान बनाए, लेकिन लगभग दोगुने प्रदर्शन के साथ सबसे अच्छा एक घातक दोष था (पूरी तरह से संलग्न समय सीमाओं को सही ढंग से संभालना नहीं)। दूसरे के पास बहुत अधिक/खराब आँकड़े थे (जो मुझे पता था लेकिन कोशिश करनी थी)।
स्पष्टीकरण
प्रत्येक पंक्ति से सभी समापन बिंदु समयों का उपयोग करते हुए, प्रत्येक समापन बिंदु समय को डुप्लिकेट करके और फिर इस तरह से समूहबद्ध करके रुचि की सभी संभावित समय सीमाओं की एक अलग सूची बनाएं ताकि हर बार अगले संभावित समय के साथ जोड़ा जा सके। इन श्रेणियों के बीता हुआ मिनटों का योग जहां कहीं भी वे किसी वास्तविक कार्यकर्ता के काम करने के समय के साथ मेल खाते हैं।