Quería saber cuál de los siguientes dos enfoques es más rápido:
1) tres 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
con FROM
-cláusula:
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;
Me sorprendió que la diferencia sea tan grande. La primera consulta con tres subconsultas devuelve el resultado inmediatamente, mientras que el segundo SUM
enfoque necesita 18 segundos.
Claims
es una vista que selecciona de una tabla que contiene ~ 18 millones de filas. Hay un índice en la columna FK de la ClaimStatus
tabla que contiene el nombre de estado.
¿Por qué hace una gran diferencia si uso COUNT
o SUM
?
Planes de ejecución:
Hay 12 estados en total. Esos tres estados pertenecen al 7% de todas las filas.
Esta es la vista real, no estoy seguro si es relevante:
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
fuente
fuente
COUNT
versión del plan. ¿Puedes editar el me gusta de laSUM
versión para señalar el plan correcto?Authorized
.WHERE c.Status = 'Approved' or c.Status = 'Valid' or c.status = 'Reject'
a laSUM
variante?Respuestas:
La
COUNT(*)
versión puede buscar simplemente el índice que tiene en la columna de estado una vez para cada estado que está seleccionando, mientras que laSUM(...)
versión necesita buscar el índice doce veces (el número total de tipos de estado únicos).Claramente, buscar un índice tres veces será más rápido que buscarlo 12 veces.
El primer plan requiere una concesión de memoria de 238 MB, mientras que el segundo plan requiere una concesión de memoria de 650 MB. Es posible que la concesión de memoria más grande no se pueda completar de inmediato, lo que hace que la consulta sea mucho más lenta.
Modifique la segunda consulta para que sea:
Esto permitirá que el optimizador de consultas elimine el 75% de las búsquedas de índice, y debería dar como resultado una concesión de memoria requerida menor, menores requisitos de E / S y un tiempo de resultado más rápido.
La
SUM(CASE WHEN ...)
construcción esencialmente evita que el optimizador de consultas empuje losStatus
predicados hacia la parte de búsqueda de índice del plan.fuente
max server memory
opción: debe configurarse con el valor correcto para su sistema. Es posible que desee ver esta pregunta y las respuestas para obtener detalles sobre cómo hacerlo.