2014-07-18 50 views
5

我有一個SQL查詢需要7分鐘+才能返回結果。我試圖儘可能地進行優化,並且執行計劃在哈希匹配(總計)上損失了82%的時間。我已經做了一些搜索,看起來像使用「EXISTS」將有助於解決,但我還沒有弄清楚查詢的語法使其工作。以下是查詢:優化SQL查詢以避免哈希匹配(Aggregate)

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的連接?或者如果有更好的方法來優化,我也爲此而努力。謝謝

回答

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

的語句看起來結構合理,並沒有看到優化了巨大的範圍提供的每requisits得到解決,如

  1. 檢查索引碎片並確保所有索引得到維護
  2. 檢查統計信息是否最新
  3. 如果髒的準備好可以接受,那麼值得考慮在桌上應用WITH(NOLOCK)。
  4. 如果查詢允許聲明變量,那麼將DATEADD移出Filter語句如下所示可能會有所幫助。

希望這會有所幫助。

-- 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

的共-worker分解了查詢並以較小的塊取出數據,因此對連接返回的數據沒有太多的處理。它把它縮減到不到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

至少我會開始擺脫所有這些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勝過常規查詢的場合。你的初始查詢看起來很好,除了上面提到的過度使用OR之外,所以我會在下一個索引中看到。