SQL Server通过查找执行相同类型连接的另一种方法来提高脚本性能

时间:2015-08-03 12:02:05

标签: sql performance sql-server-2012

我有一个脚本,在给定的时间段内只返回有问题的行,并复制超过60秒发送的任何行。这可以通过以下连接来实现:

FROM Table t
INNER JOIN CTE_DayHourMinutes dhm ON
Calculate_Date >= t.[Start Date]
AND 
dhm.Calculate_Date <= t.[End Date]

对于表t中的每个记录,它与计算日期的YYYY-MM-DD HH-MM-SS匹配在一起。唯一的问题是返回100条记录需要10分钟左右。最终,该脚本应在一个系统内部使用,该系统可能有数千甚至数百万行,因为我们希望能够获得三个月的数据。

我还应该提一下,我已经测试了脚本的其余部分,并且每个工作正常并且在运行必要的CTE和其他部分时没有性能问题。唯一的问题是我尝试进行上述连接的方式以及它必须检查的行数,目前这需要太长时间。

因此,我不知道如何以类似的方式实现上述目标,但提高了脚本的性能。

DECLARE
    @startDate DateTime 
,   @currentDate DateTime

/* Demo System */    SET @currentDate = '2014-04-26'

SET @startDate = DATEADD(day, -10 , @CurrentDate)

-- Create a list of Days (depending on the month in question)
-------------------------------------------------------------
; WITH CTE_dayList as
(
SELECT @startDate as cal_day
union all
SELECT DATEADD(DAY , 1, d1var.cal_day) as cal_day FROM CTE_daylist d1var 
WHERE  DATEADD(DAY , 1, d1var.cal_day) <= @currentDate 
)

-- Create a list of hours 0 - 23 (24 hours)
-------------------------------------------
, CTE_hourList as
(
SELECT 0  as cal_hour
union all
SELECT h1var.cal_hour + 1 as cal_hour FROM CTE_hourList h1var 
WHERE h1var.cal_hour + 1 <= 23 
)

-- Create a list of minutes 0 - 59 (1 hour)
-------------------------------------------
, CTE_minuteList as
(
SELECT 0  as cal_minute
union all
SELECT m1var.cal_minute + 1 as cal_minute FROM CTE_minuteList m1var 
WHERE m1var.cal_minute + 1 <= 59 
)

-- Create a day , hour and minnute -- cross join the hour and minute onto each day between the two dates.

, CTE_DayHourMinutes as
(
SELECT
    -- cast the cal_day (date) with the hours and minute, to create a date and time.
    CAST(CAST(cal_day AS VARCHAR) + CAST(CAST(cal_hour as VARCHAR) + ':' + CAST(cal_minute AS VARCHAR) AS DATETIME) AS DATETIME) AS Calculate_Date
FROM CTE_dayList  
CROSS JOIN
(SELECT cal_hour , cal_minute FROM CTE_hourList CROSS JOIN CTE_minuteList) DHMList)

-- create transmission end date and time ( required for the join in the main select statement )


, CTE_Text RF as
(
SELECT
        H.ObjectGuid AS Transmission_ID
    ,   CAST(H.[TRDateTime] AS DateTime) AS [Transmission Start Date]
    ,   CAST(DATEADD(second, HT.ElapsedTime, H.TRDateTime) AS DateTime) AS [Transmission End Date]
    ,   HT.[ElapsedTime] AS [Time taken to send]
    ,   HT.GoodPageCount AS Pages
    ,   HT.[ChannelUsed]
FROM [dbo].History AS H (NOLOCK)
LEFT OUTER JOIN [dbo].HistoryTRX AS HT (NOLOCK) ON H.handle = HT.handle

)

SELECT 

        Calculate_Date AS [Full Calculated Date]
    ,   CAST(Calculate_Date AS DATE) AS Calculated_Date
    ,   CAST(DATEPART(YYYY , dhm.Calculate_Date) AS VARCHAR ) + '-' + RIGHT('0' + CAST(DATEPART(Month , dhm.Calculate_Date) AS VARCHAR) , 2) AS [Calculated Year-Month]
    ,   CAST(DATEPART(YYYY , dhm.Calculate_Date) AS VARCHAR ) + '-' + RIGHT('0' + CAST(DATEPART(Week , dhm.Calculate_Date) AS VARCHAR) , 2)  AS [Calculated Year-Week]
    ,   CAST(DATEPART(YYYY , dhm.Calculate_Date) AS VARCHAR ) + '-' + RIGHT('0' + CAST(DATEPART(DAY , dhm.Calculate_Date) AS VARCHAR) , 2)   AS [Calculated Year-Day]

    ,   DATEPART(YYYY, dhm.Calculate_Date)                                  AS [Calculated Year]
    ,   RIGHT('0' + CAST(DATEPART(MM, dhm.Calculate_Date) AS VARCHAR) ,2)   AS [Calculated Month]
    ,   DATEPART(Week, dhm.Calculate_Date)                                  AS [Calculated Week]
    ,   DATEPART(DAY, dhm.Calculate_Date)                                   AS [Calculated Day]

   ,    RF.Transmission_ID
   ,    RF.[Transmission Start Date]
   ,    RF.[Transmission End Date]
   ,    RIGHT('0' + CAST(DATEPART(HOUR , RF.[Transmission Start Date]) AS VARCHAR) ,2) + ':' + RIGHT('0' + CAST(DATEPART(Minute , RF.[Transmission Start Date]) AS VARCHAR) ,2) AS [Transmission Start Time]
   ,    RIGHT('0' + CAST(DATEPART(HOUR , RF.[Transmission End Date]) AS VARCHAR) ,2) + ':' + RIGHT('0' + CAST(DATEPART(Minute , RF.[Transmission End Date]) AS VARCHAR) ,2) AS [Transmission End Time]
   ,    RF.[Time taken to send]
   ,    RF.Pages
   ,    RF.[ChannelUsed]

FROM CTE_Text RF
INNER JOIN CTE_DayHourMinutes dhm ON

        -- Join where the calculate_date is between the start and end date of the transmission date.           
           dhm.Calculate_Date >= RF.[Transmission Start Date]
           AND 
           dhm.Calculate_Date <= RF.[Transmission End Date]

1 个答案:

答案 0 :(得分:0)

我会根据你上面提到的代码以及对数据类型和表格模型,现有索引或pk等缺失的一些猜测来建议以下这些更改。更新/信息会很好。

  • 我认为数据类型如下

    • 创建表历史记录(

      ObjectGuid uniqueidentifier
      TRDateTime datetime
      handle bigint
      
    • HistoryTRX

      ElapsedTime int
      GoodPageCount int
      ChannelUsed int
      handle bigint
      
  • 尽管它没有改善整个查询,但CTE_DayHourMinutes更快更短:

    ; with CTE_DayHourMinutes(Calculate_Date) as (
    select @startDate
    union all 
    select DATEADD(MINUTE, 1, Calculate_Date) from CTE_DayHourMinutes 
    where Calculate_Date<DATEADD(MINUTE, 60*24-1, @currentDate)
    )
    Select Calculate_Date From  CTE_DayHourMinutes
    Option (MaxRecursion 0)
    
  • CTE_Text RF表扫描

    您应该首先尽快加入[dbo] .History和CTE_DayHourMinutes,并尝试减少此CTE和历史记录表的范围。现在您可能正在扫描整个历史记录表+历史记录表格的全部或部分

  • LEFT OUTER JOIN [dbo] .HistoryTRX

    当两个表之间没有匹配时,HT.ElapsedTime为空。因此,[传输结束日期]为空并且dhm.Calculate_Date&gt; = RF。[传输开始日期] AND dhm.Calculate_Date&lt; = RF。[传输结束日期]不匹配。您可能需要内部联接和/或需要查看/重新考虑您想要实现的目标。

  • 尽可能删除演员和功能

    看起来大多数都不需要。它们也阻止了索引的正确使用。

  • 查看索引

    它们是否设置正确且有用?