2014-07-18 13 views
5

Tôi có một truy vấn SQL mất 7 phút + để trả lại kết quả. Tôi đang cố gắng tối ưu hóa càng nhiều càng tốt và kế hoạch thực hiện mất 82% thời gian trên một trận đấu băm (tổng hợp). Tôi đã thực hiện một số tìm kiếm và trông giống như bằng cách sử dụng một "EXISTS" sẽ giúp giải quyết, nhưng tôi đã không tìm ra cú pháp của truy vấn để làm cho nó hoạt động. Đây là truy vấn:Tối ưu hóa truy vấn SQL để tránh Hash Match (Tổng hợp)

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; 

Làm cách nào để giảm/loại bỏ các kết nối bằng EXISTS? Hoặc nếu có cách nào tốt hơn để tối ưu hóa, tôi cũng sẽ làm như vậy. Cảm ơn

Trả lời

2

Tôi sẽ bắt đầu bằng cách kiểm tra các chỉ mục. Tất cả các khóa được sử dụng trong kết nối được xác định là primary keys? Hay ít nhất họ cũng có chỉ mục?

Sau đó, chỉ số bổ sung về ProcessorServer có thể giúp:

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

Tuyên bố trông có cấu trúc hợp lý và không thấy một phạm vi rất lớn để tối ưu hóa cung cấp cho mỗi requisits được giải quyết như

  1. Kiểm tra phân mảnh chỉ mục và đảm bảo tất cả chỉ mục được duy trì
  2. Kiểm tra xem Thống kê có được cập nhật hay không
  3. Nếu bẩn sẵn sàng chấp nhận được thì đáng xem xét áp dụng WITH (NOLOCK) trên bàn.
  4. Nếu truy vấn cho phép khai báo biến thì di chuyển DATEADD ra khỏi câu lệnh Bộ lọc như dưới đây có thể mang lại lợi ích.

Hy vọng điều này sẽ hữu ích.

-- 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 NGÀY

SET @dt_Yesterdate = DATEADD (NGÀY, - (1), CHUYỂN ĐỔI (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

Một đồng -người làm việc đã phá vỡ truy vấn và rút ra dữ liệu trong các đoạn nhỏ hơn để không có quá nhiều xử lý dữ liệu được trả về bởi các phép nối. Nó cắt nó xuống dưới 1 giây trở lại. Truy vấn mới:

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; 

Cảm ơn tất cả các đề xuất.

1

Ít nhất tôi bắt đầu với việc loại bỏ tất cả các mệnh đề HOẶC đó.

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

và thay thế bằng

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

Tôi không chắc về chuyển đổi tất cả mọi thứ để CTEs mặc dù. Bạn không thể lập chỉ mục CTE và tôi chưa gặp một sự kiện nào mà CTE hoạt động tốt hơn truy vấn thông thường. Truy vấn ban đầu của bạn dường như được hình thành tốt ngoài việc sử dụng OR quá mức như đã đề cập ở trên, vì vậy tôi sẽ xem xét các chỉ mục tiếp theo.

Các vấn đề liên quan