Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何优化SQL查询以更快地运行?_Sql_Sql Server_Optimization_Lag - Fatal编程技术网

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

如何优化SQL查询以更快地运行?,sql,sql-server,optimization,lag,Sql,Sql Server,Optimization,Lag,这比我想要运行这个查询的时间要长得多,一分钟后,我猜这与服务器有很大关系,但我想我会问一下,是否有人想过加快这个速度 查询的目的是获取一些电话代理数据,这些数据不是由任何表汇总的 acd=入站呼叫 aod=拨号器呼叫 手动=手动呼叫 联系人=基于代理将使用的处置代码 success=是联系人的子集 您需要删除子查询并将 SELECT b.User_Id ,(CONVERT(varchar, DATEADD(hh, - 7, b.callstartdt), 101))as 'Dt'

这比我想要运行这个查询的时间要长得多,一分钟后,我猜这与服务器有很大关系,但我想我会问一下,是否有人想过加快这个速度

查询的目的是获取一些电话代理数据,这些数据不是由任何表汇总的

  • acd=入站呼叫
  • aod=拨号器呼叫
  • 手动=手动呼叫
  • 联系人=基于代理将使用的处置代码
  • success=是联系人的子集

您需要删除子查询并将

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
在临时表中,并将该临时表连接到Disp_ID上的[detail_epro].[dbo].[AgentDispoDetail]

正如其他人已经发布的,为什么要使用转换来比较日期?每个表上的格式是否不同?如果没有,请删除转换


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

该查询存在许多问题,但我注意到的第一件事是datetime转换效率低下。因此,在检查索引和执行计划之前,我首先从这一部分开始

我想您应该检查不同的日期时间是否在同一日期(减去7小时,这可能是数据存储在UTC时的时区)。所以,让我们试试这个,而不是那个(可怕的)
,其中

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)
交叉应用
(选择dt=DATEADD(小时-7,b.CallStartDt))作为x
交叉应用
(选择dt=DATEADD(day,+1,x.dt))作为y
哪里
b、 CallStartDt>=DATEADD(小时,+7,'20140801')
c.CallStartDt>=x.dt和c.CallStartDt=x.dt和d.CallStartDt=x.dt和e.CallStartDt=x.dt和es.CallStartDt
解释/说明:

  • (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%安全格式。请参阅:

  • 使用
    DATEADD()
    函数,使用长表单<代码>小时
    而不是
    hh
    而不是
    dd
    分钟
    而不是
    mm
    (或者它是
    mi
    ?,或者
    min
    ,我总是忘了)更不容易出错

还有更多工作要做:

  • 上述4个条件(关于
    c
    d
    e
    es
    表的条件)可能应该移动到相应的
    左侧
    联接(如DRapp所述)

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

次要细节:

  • 避免使用单引号和别名。使用不带引号的别名,如果需要,也可以使用双引号。请参阅(另一篇亚伦·伯特朗的博客文章):

作为一个更新,因为我没有发布答案,我最终用临时表将许多查询分为较小的查询,这样做可以加快查询和处理速度1000%

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


谢谢所有

不确定你的位置,但是你可能要考虑的更好的UTC转换是

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

这也是夏令时的原因,同样取决于您所在的地区

究竟为什么要将日期时间转换为
VARCHAR
,甚至更糟糕的是,转换为
'08/01/2014'
格式?这里,看看公认的答案,了解解释是什么,如果必须这样设置,那么我会考虑使用DatePart,而不是转换整个日期,当您铸造日期并进行比较时,sql必须逐个字符地检查每个日期字符并比较每个单独的字符。现在,您的每个日期比较都在进行十次比较,而不是一次比较。除了其他人扔进环中的内容外,您还保留了连接,但在WHERE子句中,显式测试了各自的“c”、“d”、“e”和“es”别名之间的相等性,从而将其转换为所有内部连接。这是你的意图吗?我解释了我认为上面的日期是怎么回事(我猜它们存储为datetime,这意味着它们永远不会完全匹配临时表)+1,并且在比较的两边都删掉-7。+1-假设他是在2005年或更晚,但比1好得多converts@twelfth. Thnx。我想你说的是交叉应用。这可以改变,但是表达式必须被写四次。这不是效率的问题,只是代码少了一点。@ypercube哇。。。我感谢所有的反馈…每天学习!我欣赏所有的反馈并阅读最佳实践!
    dateadd(minute, datediff(minute, sysutcdatetime(), sysdatetime()), b.callstartdt)