优化SQL查询以避免哈希匹配(聚合)

时间:2014-07-18 11:42:49

标签: sql sql-server performance

我有一个SQL查询,需要7分钟+才能返回结果。我试图尽可能地进行优化,并且执行计划在Hash Match(Aggregate)上丢失了82%的时间。我已经做了一些搜索,看起来像使用" EXISTS"将有助于解决,但我还没有弄清楚查询的语法,使其工作。这是查询:

select dbo.Server.Name,
                dbo.DiskSpace.Drive,
                AVG(dbo.DiskSpace.FreeSpace) as 'Free Disk Space',
                AVG(dbo.Processor.PercentUsed) as 'CPU % Used',
                AVG(dbo.Memory.PercentUtilized) as '% Mem Used'

                from Server
                join dbo.DiskSpace on dbo.Server.ID=DiskSpace.ServerID
                join dbo.Processor on dbo.Server.ID=Processor.ServerID
                join dbo.Memory on dbo.Server.ID=dbo.Memory.ServerID

                where
                dbo.Processor.ProcessorNum='_Total' 
                    and dbo.Processor.Datetm>DATEADD(DAY,-(1),(CONVERT (date, GETDATE()))) 
                    and (      dbo.Server.Name='qp-ratking' 
                            or dbo.Server.Name='qp-hyper2012' 
                            or dbo.Server.Name='qp-hyped' 
                            or dbo.Server.Name='qp-lichking')
                Group By dbo.server.name, Dbo.DiskSpace.Drive
                Order By Dbo.Server.Name, dbo.DiskSpace.Drive;

如何使用EXISTS减少/消除连接?或者,如果有更好的优化方法,我也是这样做的。感谢

4 个答案:

答案 0 :(得分:5)

一位同事打破了查询并以较小的块的形式提取数据,因此没有对连接返回的数据进行处理。它将其减少到不到1秒的回报。新查询:

WITH tempDiskSpace AS
(
SELECT dbo.Server.Name
      ,dbo.DiskSpace.Drive
      ,AVG(dbo.DiskSpace.FreeSpace) AS 'Free Disk Space'

FROM dbo.DiskSpace
      LEFT JOIN dbo.Server ON dbo.DiskSpace.ServerID=Server.ID

WHERE dbo.DiskSpace.Datetm>DATEADD(DAY,-(1),(CONVERT (date, GETDATE())))
AND (dbo.Server.Name='qp-ratking'
      OR dbo.Server.Name='qp-hyper2012'
      OR dbo.Server.Name='qp-hyped'
      OR dbo.Server.Name='qp-lichking')

GROUP BY Name, Drive
)
,tempProcessor
AS
(
SELECT dbo.Server.Name
      ,AVG(dbo.Processor.PercentUsed) AS 'CPU % Used'

FROM dbo.Processor
      LEFT JOIN dbo.Server ON dbo.Processor.ServerID=Server.ID

WHERE dbo.Processor.Datetm>DATEADD(DAY,-(1),(CONVERT (date, GETDATE())))
AND dbo.Processor.ProcessorNum='_Total'
AND (dbo.Server.Name='qp-ratking'
      OR dbo.Server.Name='qp-hyper2012'
      OR dbo.Server.Name='qp-hyped'
      OR dbo.Server.Name='qp-lichking')

GROUP BY Name
)
,tempMemory
AS
(
SELECT dbo.Server.Name
      ,AVG(dbo.Memory.PercentUtilized) as '% Mem Used'

FROM dbo.Memory
      LEFT JOIN dbo.Server ON dbo.Memory.ServerID=Server.ID

WHERE dbo.Memory.Datetm>DATEADD(DAY,-(1),(CONVERT (date, GETDATE())))
AND (dbo.Server.Name='qp-ratking'
      OR dbo.Server.Name='qp-hyper2012'
      OR dbo.Server.Name='qp-hyped'
      OR dbo.Server.Name='qp-lichking')

GROUP BY Name
)

SELECT tempDiskSpace.Name, tempDiskSpace.Drive, tempDiskSpace.[Free Disk Space], tempProcessor.[CPU % Used], tempMemory.[% Mem Used]
FROM tempDiskSpace
LEFT JOIN tempProcessor ON tempDiskSpace.Name=tempProcessor.Name
LEFT JOIN tempMemory ON tempDiskSpace.Name=tempMemory.Name
ORDER BY Name, Drive;

感谢所有建议。

答案 1 :(得分:2)

我首先检查索引。联接中使用的所有密钥是否都定义为primary keys?或者他们至少有索引?

然后,ProcessorServer上的其他索引可能有所帮助:

create index idx_Processor_ProcessorNum_Datetm_ServerId on ProcessorNum(ProcessorNum, Datetm, ServerId);
create index idx_Server_Name_ServerId on Server(Name, ServerId)

答案 2 :(得分:2)

该声明看起来结构合理,并没有看到很大的优化范围,只要满足每个要求,例如

  1. 检查索引碎片并确保维护所有索引
  2. 检查统计信息是否是最新的
  3. 如果脏的准备好是可以接受的,那么值得考虑在桌子上应用WITH(NOLOCK)。
  4. 如果查询允许声明变量,那么将DATEADD移出Filter语句如下所示可能是有益的。
  5. 希望这有帮助。

    -- Assuming Variables can be declared see the script below. 
    -- I made a few changes per my coding standard only to help me read better.
    
      

    DECLARE @dt_Yesterdate DATE

         

    SET @dt_Yesterdate = DATEADD(DAY, - (1),CONVERT(DATE,GETDATE()))

    SELECT s.Name,
           ds.Drive,
           AVG(ds.FreeSpace) AS 'Free Disk Space',
           AVG(P.PercentUsed) AS 'CPU % Used',
           AVG(m.PercentUtilized) AS '% Mem Used'
    FROM Server s
         JOIN dbo.DiskSpace AS ds
             ON s.ID = ds.ServerID
         JOIN dbo.Processor AS p
             ON s.ID = p.ServerID
         JOIN dbo.Memory AS m
             ON s.ID = m.ServerID
    WHERE P.ProcessorNum = '_Total'
      AND P.Datetm > @dt_Yesterdate
      AND s.Name IN ('qp-ratking', 'qp-hyper2012', 'qp-hyped','qp-lichking')
    GROUP BY s.name, ds.Drive
    ORDER BY s.Name, ds.Drive;
    

答案 3 :(得分:1)

至少我开始摆脱所有这些OR条款。

AND (dbo.Server.Name='qp-ratking'
      OR dbo.Server.Name='qp-hyper2012'
      OR dbo.Server.Name='qp-hyped'
      OR dbo.Server.Name='qp-lichking')

并替换为

AND dbo.Server.Name in ('qp-ratking','qp-hyper2012','qp-hyped','qp-lichking')  

我不确定是否将所有内容都转换为CTE。你不能索引CTE,我还没有遇到CTE优于常规查询的场合。除了上面提到的过度使用OR之外,你的初始查询看起来很好,所以接下来我会查看索引。

相关问题