Tengo una consulta donde usar select *
no solo hace muchas menos lecturas, sino que también usa significativamente menos tiempo de CPU que usarselect c.Foo
.
Esta es la consulta:
select top 1000 c.ID
from ATable a
join BTable b on b.OrderKey = a.OrderKey and b.ClientId = a.ClientId
join CTable c on c.OrderId = b.OrderId and c.ShipKey = a.ShipKey
where (a.NextAnalysisDate is null or a.NextAnalysisDate < @dateCutOff)
and b.IsVoided = 0
and c.ComplianceStatus in (3, 5)
and c.ShipmentStatus in (1, 5, 6)
order by a.LastAnalyzedDate
Esto terminó con 2,473,658 lecturas lógicas, principalmente en la Tabla B. Usó 26,562 CPU y tuvo una duración de 7,965.
Este es el plan de consulta generado:
En PasteThePlan: https://www.brentozar.com/pastetheplan/?id=BJAp2mQIQ
Cuando me cambio c.ID
a*
, la consulta terminó con 107.049 lecturas lógicas, distribuidas de manera bastante uniforme entre las tres tablas. Usó 4,266 CPU y tuvo una duración de 1,147.
Este es el plan de consulta generado:
En PasteThePlan: https://www.brentozar.com/pastetheplan/?id=SyZYn7QUQ
Intenté usar las sugerencias de consulta sugeridas por Joe Obbish, con estos resultados:
select c.ID
sin sugerencia: https://www.brentozar.com/pastetheplan/?id=SJfBdOELm
select c.ID
con sugerencia: https://www.brentozar.com/pastetheplan/ ? id = B1W ___ N87
select *
sin pista: https://www.brentozar.com/pastetheplan/?id=HJ6qddEIm
select *
con pista: https://www.brentozar.com/pastetheplan/?id=rJhhudNIQ
El uso de la OPTION(LOOP JOIN)
sugerencia con select c.ID
redujo drásticamente el número de lecturas en comparación con la versión sin la sugerencia, pero todavía está haciendo aproximadamente 4 veces el número de lecturas de la select *
consulta sin ninguna sugerencia. Agregando OPTION(RECOMPILE, HASH JOIN)
a laselect *
consulta hizo que funcione mucho peor que cualquier otra cosa que haya intentado.
Después de actualizar las estadísticas en las tablas y sus índices utilizando WITH FULLSCAN
, la select c.ID
consulta se ejecuta mucho más rápido:
select c.ID
antes de la actualización: https://www.brentozar.com/pastetheplan/?id=SkiYoOEUm
select *
antes de la actualización: https://www.brentozar.com/ pastetheplan /? id = ryrvodEUX
select c.ID
después de la actualización: https://www.brentozar.com/pastetheplan/?id=B1MRoO487
select *
después de la actualización: https://www.brentozar.com/pastetheplan/?id=Hk7si_V8m
select *
todavía tiene un rendimiento superior select c.ID
en términos de duración total y lecturas totales ( select *
tiene aproximadamente la mitad de las lecturas) pero usa más CPU. En general, están mucho más cerca que antes de la actualización, sin embargo, los planes aún difieren.
Se observa el mismo comportamiento en 2016 en el modo de compatibilidad de 2014 y en 2014. ¿Qué podría explicar la disparidad entre los dos planes? ¿Podría ser que no se hayan creado los índices "correctos"? ¿Podrían las estadísticas estar un poco desactualizadas causar esto?
Intenté mover los predicados a la ON
parte de la unión, de varias maneras, pero el plan de consulta es el mismo cada vez.
Después de reconstrucciones de índice
Reconstruí todos los índices en las tres tablas involucradas en la consulta. c.ID
sigue haciendo la mayor cantidad de lecturas (más del doble *
), pero el uso de la CPU es aproximadamente la mitad de la *
versión. La c.ID
versión también se derramó en tempdb en la clasificación de ATable
:
c.ID
: https://www.brentozar.com/pastetheplan/?id=HyHIeDO87
*
: https://www.brentozar.com/pastetheplan/?id=rJ4deDOIQ
También intenté forzarlo a funcionar sin paralelismo, y eso me dio la mejor consulta: https://www.brentozar.com/pastetheplan/?id=SJn9-vuLX
Noté el recuento de ejecuciones de operadores DESPUÉS de la búsqueda de índice grande que está haciendo que la orden solo se ejecute 1,000 veces en la versión de subproceso único, pero hizo mucho más en la versión paralela, entre 2,622 y 4,315 ejecuciones de varios operadores.
select c.ID
consulta mucho más rápido, pero todavía está haciendo un trabajo adicional que laselect *
consulta, sin pistas, hace.Las estadísticas obsoletas ciertamente pueden hacer que el optimizador elija un método deficiente para encontrar los datos. ¿Has intentado hacer un
UPDATE STATISTICS ... WITH FULLSCAN
o haciendo un completoREBUILD
en el índice? Intenta eso y mira si ayuda.ACTUALIZAR
Según una actualización del OP:
Entonces, ahora, si la única acción que se tomó fue
UPDATE STATISTICS
, intente hacer un índiceREBUILD
(noREORGANIZE
), ya que he visto esa ayuda con los recuentos de filas estimados donde ambosUPDATE STATISTICS
y el índiceREORGANIZE
no.fuente
a) reescribir cada tabla como una subconsulta, siguiendo estas reglas:
b) SELECCIONAR - colocar columnas de unión primero
c) PREDICADOS - moverse a sus respectivas subconsultas
d) ORDENAR POR - moverse a su respectivas subconsultas, ordene en UNIR COLUMNAS PRIMERO
e) Agregue una consulta de contenedor para su clasificación final y SELECCIONE.
La idea es ordenar previamente las columnas de unión dentro de cada subselección, colocando las columnas de unión primero en cada lista de selección.
Esto es lo que quiero decir ...
fuente
ORDER BY
Intenté esto, pero no es válido en una subconsulta sin TOP, FORXML, etc. Lo intenté sin lasORDER BY
cláusulas pero era el mismo plan.