Je voulais savoir laquelle des deux approches suivantes est la plus rapide:
1) Trois COUNT
:
SELECT Approved = (SELECT COUNT(*) FROM dbo.Claims d
WHERE d.Status = 'Approved'),
Valid = (SELECT COUNT(*) FROM dbo.Claims d
WHERE d.Status = 'Valid'),
Reject = (SELECT COUNT(*) FROM dbo.Claims d
WHERE d.Status = 'Reject')
2) SUM
avec FROM
-clause:
SELECT Approved = SUM(CASE WHEN Status = 'Approved' THEN 1 ELSE 0 END),
Valid = SUM(CASE WHEN Status = 'Valid' THEN 1 ELSE 0 END),
Reject = SUM(CASE WHEN Status = 'Reject' THEN 1 ELSE 0 END)
FROM dbo.Claims c;
J'ai été surpris que la différence soit si grande. La première requête avec trois sous-requêtes renvoie le résultat immédiatement tandis que la deuxième SUM
approche nécessite 18 secondes.
Claims
est une vue qui sélectionne dans un tableau contenant environ 18 millions de lignes. Il y a un index sur la colonne FK de la ClaimStatus
table qui contient le nom d'état.
Pourquoi est-ce si important que j'utilise COUNT
ou SUM
?
Plans d'exécution:
Il y a 12 statuts au total. Ces trois statuts appartiennent à 7% de toutes les lignes.
Ceci est la vue réelle, je ne sais pas si elle est pertinente:
CREATE VIEW [dbo].[Claims]
AS
SELECT
mu.Marketunitname AS MarketUnit,
c.Countryname AS Country,
gsp.Gspname AS GSP,
gsp.Wcmskeynumber AS GspNumber,
sl.Slname AS SL,
sl.Wcmskeynumber AS SlNumber,
m.Modelname AS Model,
m.Salesname AS [Model-Salesname],
s.Claimstatusname AS [Status],
d.Work_order AS [Work Order],
d.Ssn_number AS IMEI,
d.Ssn_out,
Remarks,
d.Claimnumber AS [Claim-Number],
d.Rma_number AS [RMA-Number],
dbo.ToShortDateString(d.Received_Date, 1) AS [Received Date],
Iddata,
Fisl,
Fimodel,
Ficlaimstatus
FROM Tabdata AS d
INNER JOIN Locsl AS sl
ON d.Fisl = sl.Idsl
INNER JOIN Locgsp AS gsp
ON sl.Figsp = gsp.Idgsp
INNER JOIN Loccountry AS c
ON gsp.Ficountry = c.Idcountry
INNER JOIN Locmarketunit AS mu
ON c.Fimarketunit = mu.Idmarketunit
INNER JOIN Modmodel AS m
ON d.Fimodel = m.Idmodel
INNER JOIN Dimclaimstatus AS s
ON d.Ficlaimstatus = s.Idclaimstatus
INNER JOIN Tdefproducttype
ON d.Fiproducttype = Tdefproducttype.Idproducttype
LEFT OUTER JOIN Tdefservicelevel
ON d.Fimaxservicelevel = Tdefservicelevel.Idservicelevel
LEFT OUTER JOIN Tdefactioncode AS ac
ON d.Fimaxactioncode = ac.Idactioncode
sql-server
performance
sql-server-2005
t-sql
Tim Schmelter
la source
la source
COUNT
version du plan. Pouvez-vous modifier laSUM
version similaire pour pointer vers le bon plan?Authorized
.WHERE c.Status = 'Approved' or c.Status = 'Valid' or c.status = 'Reject'
à laSUM
variante.Réponses:
La
COUNT(*)
version peut simplement rechercher l'index que vous avez dans la colonne d'état une fois pour chaque état que vous sélectionnez, tandis que laSUM(...)
version doit rechercher l'index douze fois (le nombre total de types d'état uniques).Il est clair que la recherche d'un indice trois fois sera plus rapide que sa recherche 12 fois.
Le premier plan nécessite une allocation de mémoire de 238 Mo, tandis que le second plan nécessite une allocation de mémoire de 650 Mo. Il se peut que la plus grande allocation de mémoire ne puisse pas être remplie immédiatement, ce qui rend la requête beaucoup plus lente.
Modifiez la deuxième requête pour qu'elle soit:
Cela permettra à l'optimiseur de requêtes d'éliminer 75% des recherches d'index, et devrait entraîner à la fois une allocation de mémoire requise inférieure, des exigences d'E / S plus faibles et un temps de résultat plus rapide.
La
SUM(CASE WHEN ...)
construction empêche essentiellement l'optimiseur de requêtes de pousser lesStatus
prédicats vers le bas dans la partie de recherche d'index du plan.la source
max server memory
option - elle doit être configurée à la valeur correcte pour votre système. Vous voudrez peut-être regarder cette question et les réponses pour plus de détails sur la façon de le faire.