improve - Rendimiento de consultas de SQL Server: eliminar la necesidad de Hash Match(unión interna)
sql server performance monitoring (2)
Primeros pensamientos:
- Cambiar a EXISTS (cambia equi-join a semi-join)
- Debe tener índices en t1.StatusId, t5.TypeId e INCLUDE t1.AdditionalColumnID
No me preocuparía por tu método de unión todavía ...
Personalmente, nunca he usado una sugerencia de ÚNETE. Solo funcionan para los datos, índices y estadísticas que tiene en ese momento. A medida que estos cambian, su sugerencia ÚNETE limita al optimizador.
select t1.PrimaryKeyId, t1.AdditionalColumnId
from
TableOne t1
where
t1.Status = 1
AND EXISTS (SELECT *
FROM
TableThree t3
join TableFour t4 on t3.ForeignKeyId = t4.PrimaryKeyId
join TableFive t5 on t4.ForeignKeyId = t5.PrimaryKeyId
WHERE
t1.PrimaryKeyId = t3.ForeignKeyId
AND
t5.TypeId = 68)
AND EXISTS (SELECT *
FROM
TableTwo t2
WHERE
t1.ForeignKeyId = t2.PrimaryKeyId)
Índice para tableOne .. uno de
-
(Status, ForeignKeyId) INCLUDE (AdditionalColumnId)
-
(ForeignKeyId, Status) INCLUDE (AdditionalColumnId)
Índice para tableFive ... probablemente (typeID, PrimaryKeyId)
Edición: se unió a JOINS y EXISTS para que coincida con las correcciones de preguntas
Tengo la siguiente consulta, que está haciendo muy poco y es un ejemplo del tipo de combinaciones que estoy haciendo en todo el sistema.
select t1.PrimaryKeyId, t1.AdditionalColumnId
from TableOne t1
join TableTwo t2 on t1.ForeignKeyId = t2.PrimaryKeyId
join TableThree t3 on t1.PrimaryKeyId = t3.ForeignKeyId
join TableFour t4 on t3.ForeignKeyId = t4.PrimaryKeyId
join TableFive t5 on t4.ForeignKeyId = t5.PrimaryKeyId
where
t1.StatusId = 1
and t5.TypeId = 68
Hay índices en todas las columnas de unión, sin embargo, el rendimiento no es excelente. La inspección del plan de consulta revela una gran cantidad de Hash Match (Inner Joins) cuando realmente quiero ver combinaciones de Nested Loop.
El número de registros en cada tabla es el siguiente:
select count(*) from TableOne
= 64393
select count(*) from TableTwo
= 87245
select count(*) from TableThree
= 97141
select count(*) from TableFour
= 116480
select count(*) from TableFive
= 62
¿Cuál es la mejor manera de mejorar el rendimiento de este tipo de consulta?
SQL Server es bastante bueno optimizando consultas, pero también es conservador: optimiza las consultas para el peor de los casos. Una unión de bucle generalmente da como resultado una búsqueda de índice y una búsqueda de marcador para cada fila. Debido a que las uniones de bucle causan una degradación dramática para los conjuntos grandes, SQL Server no se atreve a usarlos a menos que esté seguro del número de filas.
Puede usar la forceseek
consulta de forceseek
para forzar una búsqueda de índice:
inner join TableTwo t2 with (FORCESEEK) on t1.ForeignKeyId = t2.PrimaryKeyId
Alternativamente, puede forzar una unión de bucle con la palabra clave de loop
:
inner LOOP join TableTwo t2 on t1.ForeignKeyId = t2.PrimaryKeyId
Las sugerencias de consulta limitan la libertad de SQL Server, por lo que ya no puede adaptarse a las circunstancias cambiadas. Es una buena práctica evitar las sugerencias de consulta, a menos que exista una necesidad comercial que no pueda satisfacerse sin ellas.