Gordon Linoff एक CTE आधारित उत्तर है
मैंने कुछ प्रदर्शन विश्लेषण किया है सभी कार्यशील एल्गोरिथम पर रिक्त मानों का अर्थ है कि इसमें बहुत अधिक समय लगा। इसका परीक्षण सिंगल कोर i7 X920 @2GHz चिप पर किया जाता है, जो कुछ SSD द्वारा समर्थित है। बनाया गया एकमात्र इंडेक्स UserID, AvailStart पर एक क्लस्टर था। अगर आपको लगता है कि आप किसी भी प्रदर्शन में सुधार कर सकते हैं, तो मुझे बताएं।
यह सीटीई संस्करण रैखिक से भी बदतर था, एसक्यूएल सर्वर आरएन =आरएन + 1 को एक कुशल तरीके से शामिल नहीं कर सकता। मैंने इसे नीचे एक हाइब्रिड दृष्टिकोण के साथ सुधारा है, जहां मैं पहले सीटीई को तालिका चर में सहेजता हूं और अनुक्रमित करता हूं। यह अभी भी कर्सर आधारित दृष्टिकोण से दस गुना अधिक IO लेता है।
With OrderedRanges as (
Select
Row_Number() Over (Partition By UserID Order By AvailStart) AS RN,
AvailStart,
AvailEnd
From
dbo.Available
Where
UserID = 456
),
AccumulateMinutes (RN, Accum, CurStart, CurEnd) as (
Select
RN, 0, AvailStart, AvailEnd
From
OrderedRanges
Where
RN = 1
Union All
Select
o.RN,
a.Accum + Case When o.AvailStart <= a.CurEnd Then
0
Else
DateDiff(Minute, a.CurStart, a.CurEnd)
End,
Case When o.AvailStart <= a.CurEnd Then
a.CurStart
Else
o.AvailStart
End,
Case When o.AvailStart <= a.CurEnd Then
Case When a.CurEnd > o.AvailEnd Then a.CurEnd Else o.AvailEnd End
Else
o.AvailEnd
End
From
AccumulateMinutes a
Inner Join
OrderedRanges o On
a.RN = o.RN - 1
)
Select Max(Accum + datediff(Minute, CurStart, CurEnd)) From AccumulateMinutes
http://sqlfiddle.com/#!6/ac021/2
कुछ प्रदर्शन विश्लेषण करने के बाद, यहां एक हाइब्रिड सीटीई/टेबल वैरिएबल संस्करण है जो कर्सर आधारित दृष्टिकोण को छोड़कर किसी भी चीज़ से बेहतर प्रदर्शन करता है
Create Function dbo.AvailMinutesHybrid(@UserID int) Returns Int As
Begin
Declare @UserRanges Table (
RN int not null primary key,
AvailStart datetime,
AvailEnd datetime
)
Declare @Ret int = Null
;With OrderedRanges as (
Select
Row_Number() Over (Partition By UserID Order By AvailStart) AS RN,
AvailStart,
AvailEnd
From
dbo.Available
Where
UserID = @UserID
)
Insert Into @UserRanges Select * From OrderedRanges
;With AccumulateMinutes (RN,Accum, CurStart, CurEnd) as (
Select
RN, 0, AvailStart, AvailEnd
From
@UserRanges
Where
RN = 1
Union All
Select
o.RN,
a.Accum + Case When o.AvailStart <= a.CurEnd Then
0
Else
DateDiff(Minute, a.CurStart, a.CurEnd)
End,
Case When o.AvailStart <= a.CurEnd Then
a.CurStart
Else
o.AvailStart
End,
Case When o.AvailStart <= a.CurEnd Then
Case When a.CurEnd > o.AvailEnd Then a.CurEnd Else o.AvailEnd End
Else
o.AvailEnd
End
From
AccumulateMinutes a
Inner Join
@UserRanges o On
a.RN + 1 = o.RN
)
Select
@Ret = Max(Accum + datediff(Minute, CurStart, CurEnd))
From
AccumulateMinutes
Option
(MaxRecursion 0)
Return @Ret
End
http://sqlfiddle.com/#!6/bfd94