Comparar dos consultas en SQL Server 2012


14

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

ingrese la descripción de la imagen aquí

Seleccionar propiedades Consulta 1

ingrese la descripción de la imagen aquí

Seleccionar propiedades Consulta 2

ingrese la descripción de la imagen aquí

Conclusiones:

Consulta 1

  1. Lote costo 48%
  2. Lecturas lógicas 5
  3. Lecturas físicas 2
  4. Lecturas anticipadas Lecturas: 0
  5. Tiempo de CPU: 0 ms
  6. Tiempo transcurrido 24 ms
  7. Costo estimado del subárbol: 0.0050276
  8. Compilar CPU: 2
  9. Memoria de compilación: 384
  10. Tiempo de compilación: 2

Consulta 2

  1. Lote costo 52%
  2. Lecturas lógicas 4
  3. Lecturas físicas 1
  4. Lecturas anticipadas Lecturas: 8
  5. Tiempo de CPU 0
  6. Tiempo transcurrido 23 ms
  7. Costo estimado del subárbol: 0.0054782
  8. Compilar CPU: 0
  9. Memoria de compilación: 192
  10. 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

Los comentarios no son para discusión extendida; Esta conversación se ha movido al chat .
Paul White 9

Respuestas:


10

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:

Tenga en cuenta que encontrar la mejor consulta en esta pregunta es un medio de refinar las técnicas utilizadas para compararlas.

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.


Hola de nuevo, gracias por sus puntos sobre el uso de grandes volúmenes de datos. Esta no es la primera vez que alguien lo menciona. Sin embargo, la última vez fue para considerar la posible fragmentación de las divisiones de página. En su muestra de 200,000 filas, ¿verificó la fragmentación?
Craig Efrein el

Bueno, en mi pequeño ejemplo rápido de 200k filas, no me estaba enfocando en la fragmentación, no. Pero la forma en que lo hice no habría ninguna. Creé una tabla, la rellené y luego hice los índices, por lo que eran índices recién creados. Y eso no cambiará el enfoque de mirar los planes de consulta, que parece ser la pregunta principal. El volumen de datos es grande, realmente grande, al mirar los planes de consulta con precisión. A menudo he visto casos en los que se veía genial en desarrollo (con 1-10 filas) y era horrible en producción con datos reales. Pero su enfoque es bueno y espero que esta información y la conversación en los comentarios ayuden
Mike Walsh

Dado que estamos agrupando por custid, ¿cómo hiciste que los valores custid fueran lo suficientemente aleatorios? Una cosa que recuerdo de mis lecturas es la importancia de los valores distintos. Si custid solo tuviera un pequeño número de clientes distintos, entonces el costo del agregado del flujo no sería realista.
Craig Efrein

Acabo de utilizar la función RAND para crear 100 clientes y asignar aleatoriamente uno a cada ID de pedido. Estaba haciendo una comprobación rápida. :)
Mike Walsh

Gracias Mike por toda tu ayuda. Sin embargo, una última pregunta. En las pantallas de propiedades SELECT del Plan de ejecución en 2012 que proporcioné en mi pregunta, ¿a qué valores presta atención?
Craig Efrein
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.