Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Tổng số phút giữa nhiều phạm vi ngày

Gordon Linoff câu trả lời dựa trên CTE

Tôi đã thực hiện một số phân tích hiệu suất trên tất cả các thuật toán đang hoạt động Giá trị thấp có nghĩa là nó mất quá nhiều thời gian. Điều này được thử nghiệm trên một chip Core i7 X920 @ 2GHz duy nhất, được hỗ trợ bởi một vài ổ SSD. Chỉ mục duy nhất được tạo là một cụm trên UserID, AvailStart. Nếu bạn nghĩ rằng bạn có thể cải thiện bất kỳ hiệu suất nào, hãy cho tôi biết.

Phiên bản CTE này tệ hơn tuyến tính, Máy chủ SQL không thể thực hiện kết nối RN =RN + 1 một cách hiệu quả. Tôi đã khắc phục điều này bằng một phương pháp kết hợp bên dưới, nơi tôi lưu và lập chỉ mục CTE đầu tiên vào một biến bảng. Điều này vẫn tốn IO gấp mười lần so với phương pháp dựa trên con trỏ.

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

Sau khi thực hiện một số phân tích hiệu suất, đây là phiên bản CTE / biến bảng kết hợp hoạt động tốt hơn bất kỳ thứ gì ngoại trừ phương pháp dựa trên con trỏ

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



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách nhận các giá trị Tối đa và Tối thiểu từ một Bảng bằng cách sử dụng Hàm Tổng hợp - Hướng dẫn SQL Server / TSQL Phần 129

  2. Sử dụng COLUMNPROPERTY () để trả về thông tin cột hoặc thông số trong SQL Server

  3. Chuỗi kết nối cho SQL Server 2008 R2 Phiên bản cho SQL Server Express

  4. Gọi báo cáo SSRS bằng cách nhấp vào nút và cần nhận đầu ra dưới dạng tệp PDF

  5. Các truy vấn ANSI JOIN và không phải ANSI JOIN có thực hiện khác nhau không?