如何优化我的SQL查询以更快地运行?

时间:2014-08-06 17:56:45

标签: sql sql-server optimization lag

SELECT 
   b.User_Id
   ,(CONVERT(varchar, DATEADD(hh, - 7, b.callstartdt), 101))as 'Dt'
   ,(COUNT(distinct b.SeqNum ) + Count(distinct c.SeqNum) + count(distinct d.seqnum)) as 'TotalCalls'
   ,COUNT(distinct b.SeqNum )as 'ACD'
   ,COUNT(distinct c.SeqNum)as 'AOD'
   ,COUNT(distinct d.seqnum)  as 'Manual'
   ,COUNT(distinct e.SeqNum)as 'Contacts'
   ,COUNT (distinct es.seqnum) as 'Success'
FROM 
   [detail_epro].[dbo].[ACDCallDetail]as b 
LEFT JOIN 
   [detail_epro].[dbo].[AODCallDetail]as c on c.User_Id = b.User_Id   
LEFT JOIN
   [detail_epro].[dbo].[manualCallDetail]as d on d.User_Id = b.User_Id 
LEFT JOIN
   (SELECT 
       USER_ID, CallStartDt, SeqNum
    FROM 
       [detail_epro].[dbo].[AgentDispoDetail]
    WHERE 
        Disp_Id IN 
                (100000150, 100000126,  100000137,  100000093,  100000133,  
                100000123,  100000094,  100000161,  100000162,  100000085,  
                100000084,  100000086,  100000096,  100000087,  100000157,  
                100000088,  100000097,  100000154,  100000148,  100000134,  
                100000131,  100000160,  100000156,  100000165,  100000166,  
                100000122,  100000121,  100000138,  100000130,  100000144,  
                100000132,  100000158,  100000098,  100000147,  100000100,  
                100000153,  100000139,  100000145,  100000101,  100000140,  
                100000102,  100000103,  100000104,  100000105,  100000106,  
                100000159,  100000112,  100000135,  100000090,  100000113,  
                100000141,  100000146,  100000115,  100000108,  100000092,  
                100000155,  100000125,  100000151,  100000136,  100000107,  
                100000142) 
   ) AS e ON e.User_Id = b.User_Id
LEFT JOIN 
   (SELECT 
        USER_ID, CallStartDt, SeqNum
    FROM 
        [detail_epro].[dbo].[AgentDispoDetail]
    WHERE Disp_Id IN 
                (100000150, 100000137,  100000093,  100000133,  100000123,  
                100000094,  100000161,  100000085,  100000086,  100000157,  
                100000088,  100000131,  100000160,  100000156,  100000165,  
                100000166,  100000122,  100000121,  100000138,  100000144,  
                100000132,  100000098,  100000100,  100000153,  100000139,  
                100000145,  100000101,  100000140,  100000102,  100000103,  
                100000105,  100000106,  100000159,  100000112,  100000135,  
                100000141,  100000146,  100000115,  100000108,  100000092,  
                100000155,  100000125,  100000151,  100000136,  100000107) 
   ) AS es ON es.User_Id = b.User_Id
WHERE
   (CONVERT(varchar, DATEADD(hh, - 7, b.CallStartDt), 101)) = (CONVERT(varchar, DATEADD(hh, - 7, c.CallStartDt), 101))
   AND (CONVERT(varchar, DATEADD(hh, - 7, b.CallStartDt), 101))= (CONVERT(varchar, DATEADD(hh, - 7, d.CallStartDt), 101))
   AND (CONVERT(varchar, DATEADD(hh, - 7, b.CallStartDt), 101))= (CONVERT(varchar, DATEADD(hh, - 7, e.CallStartDt), 101)) 
   AND (CONVERT(varchar, DATEADD(hh, - 7, b.CallStartDt), 101))= (CONVERT(varchar, DATEADD(hh, - 7, es.CallStartDt), 101))
   AND (CONVERT(varchar, DATEADD(hh, - 7, b.CallStartDt), 101)) >= '08/01/2014'
GROUP BY
   b.User_Id, b.CallStartDt

这比我想要运行这个查询需要更长的时间,超过一分钟,我猜它与服务器有很多关系,但我想要看看是否有人有任何想法让这更快

查询是获取一些未被任何表格汇总的电话代理数据

  • acd =入站电话
  • aod =拨打电话
  • manual = manual calls
  • contacts =基于代理人将使用的处理代码
  • success =是联系人的子集

4 个答案:

答案 0 :(得分:6)

查询存在许多问题,但我首先注意到的是日期时间转换效率低下。所以,在检查索引和执行计划之前,我首先从该部分开始。

我想您要检查各个日期时间是否在同一天(减去7小时,这可能是您的时区,而数据以UTC格式存储)。所以,试试这个,而不是那个(可怕的)WHERE

CROSS APPLY
    ( SELECT dt = DATEADD(hour, -7, b.CallStartDt) ) AS x
CROSS APPLY
    ( SELECT dt = DATEADD(day, +1, x.dt) ) AS y
WHERE
       b.CallStartDt >= DATEADD(hour, +7, '20140801')
  AND  c.CallStartDt >= x.dt AND  c.CallStartDt < y.dt
  AND  d.CallStartDt >= x.dt AND  d.CallStartDt < y.dt
  AND  e.CallStartDt >= x.dt AND  e.CallStartDt < y.dt
  AND es.CallStartDt >= x.dt AND es.CallStartDt < y.dt

说明/注释:

  • (CONVERT(varchar, DATEADD(hh, - 7, b.CallStartDt), 101)) >= '08/01/2014'完全错了。它不仅使用效率低下的转换,而且还会返回错误的结果。因为日期(字符串和日期)'08/03/2014'都在'08/01/2014'之后,但是对于其他示例,它是相反的:'09/09/2011' > '08/01/2014'但显然2011年是在2014年之前。

  • 已删除对DATEDIFF()CONVERT()的所有不必要的来电。这样,如果这些列上有索引,那么不仅会对函数进行几千次调用(或百万次,取决于您的表大小),而且优化器将能够使用各种条件的索引。

  • 只保留了b.CallStartDt的(-7小时),因为如果不改变表格就无法避免这种情况(添加带索引的计算列虽然有帮助。)

  • 对日期和日期时间使用合理的格式,例如'20140801''YYYYMMDD'),正如Aaron Bertrand的博客所解释的那样是在SQL-Server中使用日期的唯一100%安全格式。请参阅: Bad habits to kick : mis-handling date / range queries

  • 使用DATEADD()函数,使用长格式。 hour代替hhday代替ddminute代替mm(或mi?,或者min?,我一直在忘记。)不容易出错。

更多信息:

  • 上述4个条件(关于cdees表格的条件)可能应移至相应的{{1} } join(如DRapp评论。)

  • 检查执行计划以及索引是否可用和使用。

次要细节:

答案 1 :(得分:2)

您需要删除子查询并放入

WHERE Disp_Id IN 
(100000150, 100000137,  100000093,  100000133,  100000123,  
100000094,  100000161,  100000085,  100000086,  100000157,  
100000088,  100000131,  100000160,  100000156,  100000165,  
100000166,  100000122,  100000121,  100000138,  100000144,  
100000132,  100000098,  100000100,  100000153,  100000139,  
100000145,  100000101,  100000140,  100000102,  100000103,  
100000105,  100000106,  100000159,  100000112,  100000135,  
100000141,  100000146,  100000115,  100000108,  100000092,  
100000155,  100000125,  100000151,  100000136,  100000107)

在临时表中将该临时表连接到Disp_ID上的[detail_epro]。[dbo]。[AgentDispoDetail]。

正如其他人已发布的那样,您为什么要使用转换来比较日期?它们在每张桌子上的格式是否不同?如果他们没有删除转换。

此外,删除DATEADDS。您在比较中使用它们,但在等式的每一半中添加-7。这就像:X + 7 = 8 + 7.删除7s并且x的值没有改变。

答案 2 :(得分:1)

就像我没有发布答案的更新一样,我最终将很多查询分成带有临时表的较小查询,这样做加快了查询和流程1000%

最终转换为CTE并将其保存为视图

全部谢谢

答案 3 :(得分:1)

不确定您的语言环境,但您可能需要考虑更好的UTC转换

    dateadd(minute, datediff(minute, sysutcdatetime(), sysdatetime()), b.callstartdt)

还会考虑夏令时,这取决于您的语言环境。