J'ai une requête SQL qui prend 7 minutes + pour renvoyer les résultats. J'essaie d'optimiser au maximum et le plan d'exécution perd 82% du temps sur un match de hachage (agrégat). J'ai fait quelques recherches et il semble que l'utilisation d'un "EXISTS" aiderait à résoudre, mais je n'ai pas encore trouvé la syntaxe de la requête pour la faire fonctionner. Voici la requête:
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;
Comment puis-je réduire/éliminer les jointures à l'aide de EXISTS? Ou s’il existe un meilleur moyen d’optimiser, je suis partant pour cela aussi. Merci
Un collègue a décomposé la requête et extrait les données par petits morceaux, évitant ainsi autant de traitement des données renvoyées par les jointures. Il a été réduit à moins d'une seconde. Nouvelle requête:
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;
Merci pour toutes les suggestions.
Je commencerais par vérifier les index. Est-ce que toutes les clés utilisées dans la jointure sont définies comme primary keys
? Ou ont-ils au moins des index?
Ensuite, des index supplémentaires sur Processor
et Server
pourraient aider:
create index idx_Processor_ProcessorNum_Datetm_ServerId on ProcessorNum(ProcessorNum, Datetm, ServerId);
create index idx_Server_Name_ServerId on Server(Name, ServerId)
L’énoncé semble raisonnablement structuré et ne prévoit pas une marge d’optimisation considérable à condition que les conditions requises soient traitées, telles que
J'espère que cela t'aides.
-- 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;
À tout le moins, je commencerais par me débarrasser de toutes ces OR clauses.
AND (dbo.Server.Name='qp-ratking'
OR dbo.Server.Name='qp-hyper2012'
OR dbo.Server.Name='qp-hyped'
OR dbo.Server.Name='qp-lichking')
et remplacer par
AND dbo.Server.Name in ('qp-ratking','qp-hyper2012','qp-hyped','qp-lichking')
Je ne suis cependant pas sûr de tout convertir en CTE. Vous ne pouvez pas indexer les CTE et je ne suis pas encore tombé sur une occasion où les CTE surpassent une requête classique. Votre requête initiale semblait bien formée, mis à part l'utilisation excessive de OR comme mentionné ci-dessus, je regarderais donc les index par la suite.