2012-07-01 24 views
12

Acabo de recibir una pequeña pregunta. Al tratar de obtener un valor máximo único de una tabla. ¿Cuál es mejor?SQL rendimiento MAX()

SELECT MAX(id) FROM myTable WHERE (whatever) 

o

SELECT TOP 1 id FROM myTable WHERE (whatever) ORDER BY id DESC 

estoy usando Microsoft SQL Server 2012

+2

¿Lo has probado? Esperaría que fueran iguales si el optimizador es bueno. – Hogan

+1

Si 'id' es un incremento automático, esta pregunta es un duplicado de http://stackoverflow.com/questions/590079/for-autoincrement-fields-maxid-vs-top-1-id-order-by-id-desc – Ben

+0

id solo significa CUALQUIER columna de cualquier tipo –

Respuesta

26

No habrá diferencia ya que puede probarse inspeccionando los planes de ejecución. Si id es el índice agrupado, debería ver un análisis de índice agrupado ordenado; si no está indexado, seguirá viendo un escaneo de tabla o un escaneo de índice agrupado, pero no se ordenará en ninguno de los casos.

El enfoque TOP 1 puede ser útil si desea obtener otros valores de la fila, lo que es más fácil que sacar el máximo en una subconsulta y luego unir. Si desea obtener otros valores de la fila, debe dictar cómo lidiar con los vínculos en ambos casos.

Habiendo dicho eso, hay algunos escenarios en los que el plan puede ser diferente, por lo que es importante realizar la prueba dependiendo de si la columna está indexada y si aumenta monótonamente o no. Creé una tabla simple y se inserta 50000 filas:

CREATE TABLE dbo.x 
(
    a INT, b INT, c INT, d INT, 
    e DATETIME, f DATETIME, g DATETIME, h DATETIME 
); 
CREATE UNIQUE CLUSTERED INDEX a ON dbo.x(a); 
CREATE INDEX b ON dbo.x(b) 
CREATE INDEX e ON dbo.x(e); 
CREATE INDEX f ON dbo.x(f); 

INSERT dbo.x(a, b, c, d, e, f, g, h) 
SELECT 
    n.rn, -- ints monotonically increasing 
    n.a, -- ints in random order 
    n.rn, 
    n.a, 
    DATEADD(DAY, n.rn/100, '20100101'), -- dates monotonically increasing 
    DATEADD(DAY, -n.a % 1000, '20120101'),  -- dates in random order 
    DATEADD(DAY, n.rn/100, '20100101'), 
    DATEADD(DAY, -n.a % 1000, '20120101') 
FROM 
(
    SELECT TOP (50000) 
    (ABS(s1.[object_id]) % 10000) + 1, 
    rn = ROW_NUMBER() OVER (ORDER BY s2.[object_id]) 
    FROM sys.all_objects AS s1 
    CROSS JOIN sys.all_objects AS s2 
) AS n(a,rn); 
GO 

En mi sistema Estos valores creados en a/c 1-50000, b/d entre 3 y 9994, e/g de 2010-01-01 través 2011-05-16, y f/h desde 2009-04-28 hasta 2012-01-01.

Primero, comparemos las columnas enteras, a y c, indexadas monótonamente en aumento. una tiene un índice agrupado, c sin que:

SELECT MAX(a) FROM dbo.x; 
SELECT TOP (1) a FROM dbo.x ORDER BY a DESC; 

SELECT MAX(c) FROM dbo.x; 
SELECT TOP (1) c FROM dbo.x ORDER BY c DESC; 

Resultados:

enter image description here

El gran problema con la consulta cuarto es que, a diferencia de MAX, se requiere de una especie. Aquí es 3 en comparación con 4:

enter image description here

enter image description here

Este será un problema común en todas estas variaciones de consulta: a MAX contra una columna unindexed será capaz de lengüeta en el clúster escanear índice y realizar un agregado de flujo, mientras que TOP 1 necesita realizar un tipo que va a ser más caro.

Hice la prueba y vi exactamente los mismos resultados en las pruebas b + d, e + g, y f + h.

Por lo tanto, me parece que, además de producir más código normas de cumplimiento, hay un beneficio potencial de rendimiento para el uso de MAX a favor de TOP 1 en función de la tabla y los índices subyacente (que puede cambiar después de que haya puesto tu código en producción). Entonces, diría que, sin más información, es preferible MAX.

(Y como he dicho antes, TOP 1 podría ser realmente el comportamiento que está buscando, si usted está tirando de columnas adicionales. Usted querrá probar MAX + JOIN métodos, así si eso es lo que está buscando.)

+0

+1 - ¿Ha utilizado SQL para calcular sus porcentajes o ha interrogado al XML para el plan de ejecución? Sería bueno tener eso en su respuesta para que a los futuros lectores también se les dé conocimiento sobre cómo interrogar estos planes por sí mismos. – Wayne

+1

Acaba de mostrar la salida relevante de SQL Sentry Plan Explorer, una herramienta gratuita de mi empresa. http://sqlsentry.net/ –

+0

[Un buen artículo sobre la clasificación 'Top N' aquí.] (http://sqlblog.com/blogs/paul_white/archive/2010/08/27/sorting-row-goals-and -the-top-100-problem.aspx) si alguien está interesado. No tiene que ordenar realmente todas las filas (solo necesita hacer un seguimiento del 'TOP 1') pero requiere una concesión de memoria a diferencia del agregado de la secuencia. –

5

El primero de ellos es, sin duda más clara en la intención.

No debe haber una diferencia significativa de rendimiento pensada para esta consulta específica (en realidad deberían ser bastante idénticas, aunque el resultado sea diferente si no hay filas en myTable). A menos que tenga un motivo válido para ajustar la consulta (por ejemplo, un problema de rendimiento comprobado), elija siempre la que muestra la intención del código.

+3

Una ventaja adicional es que la primera consulta también es DBMS-agnóstico, lo que significa que podría tomar la misma consulta y ejecutarla en casi cualquier otro DBMS y aún así funcionaría, mientras que la segunda consulta usa el 'SQL-Server-specific 'TOP 'palabra clave que solo es compatible con SQL-Server. –

2

Todos los optimizadores de consultas que valen la pena deben producir planes de consulta con un rendimiento idéntico para ambas consultas: si se optimiza un índice en la columna, ambas consultas deberían usarlo; si no hay índice, ambos producirían un escaneo completo de la tabla.

0

Aunque sospecho que el operador de clasificación TOP 1 está sobrecargado en el plan. Intenté con TOP 1, TOP 100,> y TOP 101 y todos obtuve el mismo costo de subárbol estimado a pesar de que el último> necesitaría ordenar todas las filas. - Martin Smith Jul 2 Cuando 6:53

sea que necesite 1 fila o filas 100 el optimizador tiene que hacer misma cantidad de trabajo en este ejemplo es decir, leer todas las filas de la tabla (exploración de índice agrupado) .A continuación, ordenar todas esas filas (ordenar opertaion) ya que no hay un índice en la columna C .. Por último solo muestra cuál se necesita.

SELECT TOP (1) b FROM dbo.x ORDER BY b DESC 
option(recompile); 
SELECT TOP (100) b FROM dbo.x ORDER BY b DESC 
option(recompile); 

Pruebe el código anterior y aquí la parte superior 1 y la parte superior 100 muestra el costo de diferencia porque hay un índice en la columna b. Por lo tanto, en este caso no necesita leer todas las filas y ordenarlas, pero el trabajo es ir al puntero de la última página. Para una fila, lea la última fila en la última página del índice. TFor 100 row encuentra la última fila en la última página y luego inicia el escaneo hacia atrás hasta que obtengas las 100 filas.

+0

Esto no es correcto. Por favor, lea [el enlace que di y que explica cómo funciona el tipo 'TOP N'] (http://sqlblog.com/blogs/paul_white/archive/2010/08/27/sorting-row-goals-and-the-top -100-problema.aspx). 100 es un número mágico entre diferentes métodos, pero no parece que el cálculo de costos en el plan tenga en cuenta esto, ya que cuesta lo mismo para 'TOP 1' vs' TOP 50000' cuando se ejecuta en comparación con los datos demo de Aaron.Para 'TOP 1' básicamente solo necesita realizar un seguimiento del valor máximo que es el mismo que el de' MAX', aunque se implementa de forma diferente. No necesita ordenar las 50,000 filas. –

+0

Sin ordenar 50000 filas, ¿cómo sabría cuál es el valor máximo, si la lista está ordenada? No hay índice en la columna C. –

+0

Escaneándolos a todos y comparando cada uno con el valor 'TOP 1' que ha visto hasta ahora. No es necesario ordenar todo el conjunto de 50,000 filas en orden. –

Cuestiones relacionadas