【问题标题】:SQL Server Increase script performance by finding another way of doing the same type of joinSQL Server 通过寻找另一种执行相同类型连接的方法来提高脚本性能
【发布时间】:2015-10-25 12:40:33
【问题描述】:

我有一个脚本,它在给定的时间段内只返回有问题的行,并复制任何花费超过 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]

【问题讨论】:

  • 太宽泛了。显示更多代码(例如 CTE),以及一些基准/分析数据
  • ...以及相关的表结构包括索引和执行计划
  • 处理60秒条件的逻辑在哪里?
  • 添加了请求的代码。

标签: sql performance sql-server-2012


【解决方案1】:

我会根据您在上面放置的代码以及对缺少的内容(例如数据类型和表模型、现有索引或 pk 等)的一些猜测来建议以下这些更改。更新/信息会很好。

  • 我认为数据类型如下

    • 创建表历史记录(

      ObjectGuid uniqueidentifier
      TRDateTime datetime
      handle bigint
      
    • 历史TRX

      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 射频表扫描

    您应该尽早将 [dbo].History 与 CTE_DayHourMinutes 一起加入,并尝试缩小此 CTE 和历史表的范围。现在您可能正在扫描整个 History 表 + HistoryTRX 的全部或部分

  • 左外连接 [dbo].HistoryTRX

    当两个表不匹配时,HT.ElapsedTime 为空。因此 [Transmission End Date] 为空且 dhm.Calculate_Date >= RF.[Transmission Start Date] AND dhm.Calculate_Date

  • 尽可能去除演员表和功能

    看起来大部分都不需要。它们还会阻止正确使用索引。

  • 查看您的索引

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-27
    • 1970-01-01
    • 1970-01-01
    • 2012-04-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多