Estoy comparando dos consultas en SQL Server 2012. El objetivo es utilizar toda la información pertinente disponible del optimizador de consultas al elegir la mejor consulta. Ambas consultas producen los mismos resultados; El pedido máximo para todos los clientes.
La eliminación del grupo de búferes se realizó antes de ejecutar cada consulta con FREEPROCCACHE y DROPCLEANBUFFERS
Usando la información proporcionada a continuación, ¿qué consulta es la mejor opción?
-- Query 1 - return the maximum order id for a customer
SELECT orderid, custid
FROM Sales.Orders AS O1
WHERE orderid = (SELECT MAX(O2.orderid)
FROM Sales.Orders AS O2
WHERE O2.custid = O1.custid);
-- Query 2 - return the maximum order id for a customer
SELECT MAX(orderid), custid
FROM Sales.Orders AS O1
group by custid
order by custid
TIEMPO ESTADÍSTICO
Consulta 1 TIEMPO ESTADÍSTICO: tiempo de CPU = 0 ms, tiempo transcurrido = 24 ms
Consulta 2 ESTADÍSTICAS TIEMPO: tiempo de CPU = 0 ms, tiempo transcurrido = 23 ms
ESTADÍSTICAS IO
Consulta 1 ESTADÍSTICAS IO: Tabla 'Pedidos'. Cuenta de escaneo 1, lecturas lógicas 5, lecturas físicas 2, lecturas de lectura anticipada 0, lecturas lógicas lob 0, lecturas físicas lob 0, lecturas de lectura lob 0.
Consulta 2 ESTADÍSTICAS IO: Tabla 'Pedidos'. Recuento de escaneo 1, lecturas lógicas 4, lecturas físicas 1, lecturas anticipadas 8, lecturas lógicas lob 0, lecturas físicas lob 0, lecturas anticipadas lob 0.
Planes de ejecucion
Seleccionar propiedades Consulta 1
Seleccionar propiedades Consulta 2
Conclusiones:
Consulta 1
- Lote costo 48%
- Lecturas lógicas 5
- Lecturas físicas 2
- Lecturas anticipadas Lecturas: 0
- Tiempo de CPU: 0 ms
- Tiempo transcurrido 24 ms
- Costo estimado del subárbol: 0.0050276
- Compilar CPU: 2
- Memoria de compilación: 384
- Tiempo de compilación: 2
Consulta 2
- Lote costo 52%
- Lecturas lógicas 4
- Lecturas físicas 1
- Lecturas anticipadas Lecturas: 8
- Tiempo de CPU 0
- Tiempo transcurrido 23 ms
- Costo estimado del subárbol: 0.0054782
- Compilar CPU: 0
- Memoria de compilación: 192
- Tiempo de compilación: 0
Personalmente, aunque la consulta 2 tiene un costo de lote más alto de acuerdo con el plan gráfico, creo que es más eficiente que la consulta 1. Esto debido a que la consulta 2 requiere menos lecturas lógicas, tiene un tiempo transcurrido ligeramente menor, los valores de compilecpu, compilememory y compiletime son inferior. las lecturas de lectura anticipada son 8 para la consulta 2 y 0 para la consulta 1.
Actualización 12:03
Definición de índice agrupado
ALTER TABLE [Sales].[Orders] ADD CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED
(
[orderid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Índice no agrupado idx_nc_custid
CREATE NONCLUSTERED INDEX [idx_nc_custid] ON [Sales].[Orders]
(
[custid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
fuente
Respuestas:
Me encanta su enfoque para considerar cuidadosamente el ajuste de consultas y la revisión de opciones y planes. Desearía que más desarrolladores hicieran esto. Una advertencia sería: siempre pruebe con muchas filas, mirando las lecturas lógicas, esta es una tabla pequeña. Intente generar una carga de muestra y vuelva a ejecutar la consulta. Un pequeño problema: en su consulta superior no está solicitando un pedido, en su consulta inferior sí. Debes compararlos y contrastarlos con cada pedido.
Acabo de crear rápidamente una tabla SalesOrders con 200,000 pedidos de venta en ella, todavía no es enorme en ningún sentido de la imaginación. Y ejecutó las consultas con ORDER BY en cada una. También jugué un poco con los índices.
Sin índice agrupado en OrderID, solo un índice no agrupado en CustID La segunda consulta superó. Especialmente con el pedido por incluido en cada uno. Hubo el doble de lecturas en la primera consulta que en la segunda consulta, y los porcentajes de costo fueron 67% / 33% entre las consultas.
Con un índice agrupado en OrderID y un índice no agrupado solo en CustID , se realizaron a una velocidad similar y exactamente el mismo número de lecturas.
Por lo tanto, le sugiero que aumente el número de filas y realice algunas pruebas más. Pero mi análisis final sobre sus consultas ...
Puede encontrar que se comportan de manera más similar de lo que cree cuando aumenta las filas, así que tenga en cuenta esa advertencia y pruebe de esa manera.
Si todo lo que desea devolver es el OrderID máximo para cada Cliente, y desea determinar que, siendo el OrderID el mayor OrderID, la segunda consulta de estos dos es la mejor manera de salir de mi mentalidad: es un poco más simple y aunque un poco más caro según el costo del subárbol, es una declaración más rápida y fácil de descifrar. Si tiene la intención de agregar otras columnas en su conjunto de resultados algún día? Entonces, la primera consulta le permite hacer eso.
Actualizado: Uno de sus comentarios bajo su pregunta fue:
Pero la mejor opción para hacerlo es probar con más datos, siempre se asegura de tener datos consistentes con la producción y la producción futura esperada. Los planes de consulta comienzan a buscar datos cuando asigna más filas a las tablas, y trata de mantener la distribución de lo que esperaría en la producción. Y preste atención a cosas como incluir Order By o no, aquí no creo que haga una gran diferencia al final, pero aún así vale la pena investigar.
Su enfoque de comparar este nivel de detalle y datos es bueno. Los costos de subárbol son arbitrarios y sin sentido en su mayoría, pero aún así vale la pena al menos ver la comparación entre ediciones / cambios o incluso entre consultas. Mirar las estadísticas de tiempo y el IO son bastante importantes, al igual que mirar el plan para cualquier cosa que se sienta fuera de lugar para el tamaño de los datos con los que está trabajando y lo que está tratando de hacer.
fuente