2009-02-26 20 views
16

Quiero encontrar el valor más alto AutoIncremented de un campo. (no se va a buscar después de una inserción donde puedo usar @@SCOPE_IDENTITY, etc.) Cuál de estas dos consultas se ejecutará más rápido u ofrece un mejor rendimiento. Id es la clave principal y el campo autoincrement para Table1. Y esto es para SQL Server 2005.Para campos de autoincrement: MAX (ID) vs TOP 1 ID ORDER BY ID DESC

SELECT MAX(Id) FROM Table1 

SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC 

[Editar]
Sí en este caso Id es el campo en el que he definido el índice agrupado.
Si el índice es ID DESC entonces ¿qué ...
Y sí, sería bueno saber cómo se vería afectado el rendimiento si
1. Id es un índice agrupado + clave principal.
2. Id es un índice agrupado y no una clave principal.
3. Id es una clave primaria ASC + de índice no agrupado.
4. Id es un ASC de índice no agrupado y no la clave principal.
5. Id es una clave primaria DESC + de índice no agrupado.
6. Id es un índice DESC no agrupado y no clave principal.
7. Identificación es simplemente AutoIncrement

¡Espero que no sea una tarea difícil!

+0

De las respuestas aquí, con el índice no hay diferencia en el rendimiento. Sin embargo, he encontrado que 'MAX' /' MIN' tiene un par de ventajas. En primer lugar, como se indica a continuación, sin un índice 'MAX' será más eficaz, esto también se vuelve significativo cuando tiene uniones más complejas en su lugar. En segundo lugar, si hay valores NULL, 'SELECT MIN' devuelve un valor, pero' SELECT TOP 1 ... ASC' devuelve 'NULL' – icc97

Respuesta

7

En teoría, utilizarán los mismos planes y funcionarán casi al mismo tiempo.

En la práctica,

SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC 

más probable que se utilice un PRIMARY KEY INDEX.

Además, este es más extensible si decide seleccionar alguna columna junto con id.

un plan real de MAX() dice:

SELECT <- AGGREGATE <- TOP <- CLUSTERED INDEX SCAN 

, mientras que el plan de TOP 1 dice:

SELECT <- TOP <- CLUSTERED INDEX SCAN 

, i. mi. aggregate se omite.

El agregado en realidad no hará nada aquí, ya que solo hay una fila.

PS Como @Mehrdad Afshari@John Sansom y señaló, en un campo no indexado MAX es ligeramente más rápido (por supuesto, no 20 veces como dice optimizador):

 
-- 18,874,368 rows 

SET LANGUAGE ENGLISH 
SET STATISTICS TIME ON 
SET STATISTICS IO ON 
PRINT 'MAX' 
SELECT MAX(id) FROM master 
PRINT 'TOP 1' 
SELECT TOP 1 id FROM master ORDER BY id DESC 
PRINT 'MAX' 
SELECT MAX(id) FROM master 
PRINT 'TOP 1' 
SELECT TOP 1 id FROM master ORDER BY id DESC 
PRINT 'MAX' 
SELECT MAX(id) FROM master 
PRINT 'TOP 1' 
SELECT TOP 1 id FROM master ORDER BY id DESC 
PRINT 'MAX' 
SELECT MAX(id) FROM master 
PRINT 'TOP 1' 
SELECT TOP 1 id FROM master ORDER BY id DESC 
PRINT 'MAX' 
SELECT MAX(id) FROM master 
PRINT 'TOP 1' 
SELECT TOP 1 id FROM master ORDER BY id DESC 

Changed language setting to us_english. 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 1 ms. 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 1 ms. 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 1 ms. 
MAX 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 20 ms. 

(строк обработано: 1) 
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 447, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 5452 ms, elapsed time = 2766 ms. 
TOP 1 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 1 ms. 

(строк обработано: 1) 
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 2, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 6813 ms, elapsed time = 3449 ms. 
MAX 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 1 ms. 

(строк обработано: 1) 
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 44, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 5359 ms, elapsed time = 2714 ms. 
TOP 1 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 1 ms. 

(строк обработано: 1) 
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 6766 ms, elapsed time = 3379 ms. 
MAX 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 1 ms. 

(строк обработано: 1) 
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 5406 ms, elapsed time = 2726 ms. 
TOP 1 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 1 ms. 

(строк обработано: 1) 
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 6780 ms, elapsed time = 3415 ms. 
MAX 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 1 ms. 

(строк обработано: 1) 
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 85, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 5392 ms, elapsed time = 2709 ms. 
TOP 1 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 1 ms. 

(строк обработано: 1) 
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 10, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 6766 ms, elapsed time = 3387 ms. 
MAX 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 1 ms. 

(строк обработано: 1) 
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 5374 ms, elapsed time = 2708 ms. 
TOP 1 

SQL Server Execution Times: 
    CPU time = 0 ms, elapsed time = 1 ms. 

(строк обработано: 1) 
Table 'master'. Scan count 3, logical reads 32655, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 

SQL Server Execution Times: 
    CPU time = 6797 ms, elapsed time = 3494 ms. 
+0

Query Optimizer es determinista. ¿Cómo es que algo "más probablemente" usará un índice? –

+0

Las decisiones del optimizador dependen de las estadísticas de la tabla que dependen de los datos de la tabla que son probabilísticos. Un optimizador PUEDE decidir ordenar la tabla en lugar de usar INDEX SCAN junto con TOP. – Quassnoi

+0

Llego tarde a la fiesta, pero ¿alguna idea de cuál es la eficiencia de memoria de los dos planes para un escenario de campo indexado? Si tenemos la misma consulta corriendo una gran cantidad de veces, el plan que tome mayor buffer perderá. – vk239

3

Basta con comparar los planes de ejecución y verá (presione Ctrl+M en Management Studio al editar una consulta). Creo que estas consultas son igual de efectivas siempre que haya un índice (agrupado) en la columna Id.

Sin embargo, esto como un todo es una muy mala idea .

+0

¿Qué es una muy mala idea? – Learning

+0

Usar consultas adicionales para recuperar el ID de una fila recién agregada es una muy mala idea. Pueden ocurrir bastantes operaciones de base de datos entre estas dos solicitudes. –

+0

Oh de hecho. Muy cierto. +1 – Learning

2

MAX es generalmente más rápido.

Ambas consultas usarán el índice en la columna si existe.

Si existe ningún índice en la columna, la consulta TOP 1 utilizará un operador Top N Sort a tipo la tabla en lugar de agregar hilos de, lo que hace que sea más lenta.

MAX también proporciona una mejor legibilidad.

Nota al margen: mientras MAX utilizará un operador agregado corriente en el plan de ejecución en el caso indexada, que no tiene ningún costo específico ya que es sólo el procesamiento de una sola fila (Actual Rows = 1). Puede comparar las consultas ejecutándolas en un solo lote y ver el costo relativo. En el caso indexado, ambas consultas tendrán un costo del 50%. Probé la caja no indexada en una mesa con aproximadamente 7000 filas y TOP costará 65% en comparación con MAX que cuesta 35%.

+0

TOP 1 no ordenará la consulta. La pregunta señala explícitamente que ID es una CLAVE PRIMARIA. – Quassnoi

+0

Y creo que mencioné explícitamente "si no existe un índice en la columna". Lee más atentamente –

+0

Siempre existe un índice en una clave principal. – Quassnoi

9

Si hay un índice agrupado prácticamente no hay diferencia en el rendimiento entre las dos consultas.

Esto se debe a que ambos realizarán un Escaneo de Índice Agrupado que soportará el 100% del costo de la consulta.

Al realizar las dos consultas en una columna que no tiene un índice, se utilizan 3 operadores en ambos planes de ejecución.

La cláusula Top utiliza el operador Ordenar y la función Máx utiliza un operador Agregado de flujo.

Cuando no hay índice, la función MAX() proporciona un mejor rendimiento.

Prueba de concepto se puede encontrar tutorial y lleno de un escenario de prueba se puede encontrar here

Performance Comparison Top 1 Verses MAX() Funciton

+0

En el caso indexado, el operador agregado de la secuencia tendrá "Filas reales = 1", lo que básicamente no cuesta nada. Si no tiene un índice, el plan de ejecución para TOP 1 tendrá una clasificación de "N superior" que lo hará más lento que el "Agregado de transmisión" que usa MAX. –

+0

@Mehrdad: De hecho lo hace, los detalles completos se agregarán a mi blog. –

+0

@John, use el enlace permanente a esta pregunta en su blog http://stackoverflow.com/questions/590079/ –

2

yo sólo he probado las dos sentencias SQL que se presten a un conjunto de datos típica:

SELECT MAX(Id) FROM Table1 

SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC 

Y SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC es marginalmente más rápido porque tiene un último paso en el plan de ejecución. Estos son los planes de ejecución de cada consulta lleva a cabo:

SELECT MAX (Id) de la Tabla1

índice agrupado Scan >> inicio >> Corriente agregada >> Seleccione

SELECT TOP 1 de identificación de Tabla 1 ORDER BY Id DESC

índice agrupado Scan >> inicio >> Seleccione

1

Sí, en este caso Id es el campo en que he definido el índice agrupado . Si el índice es ID DESC, entonces qué ..Y sí que sería bueno para sabe cómo el rendimiento sería afectados si

  1. Id es un índice agrupado + clave primaria.
  2. Id es un índice agrupado y no una clave principal.
  3. Id es una clave principal ASC + de índice no agrupado.
  4. Id es un índice no agrupado ASC y no clave principal.
  5. Id es una clave primaria DESC + de índice no agrupado.
  6. Id es un índice DESC no agrupado y no clave primaria.
  7. Id es simplemente AutoIncrement

Para los casos 1 y 2, ambos llevará a cabo un recorrido de índice agrupado que devuelve un único registro. No hay diferencia de IO entre las dos consultas.

Para los casos 3, 4, 5 y 6, ambos realizarán un escaneo de índice que devuelve un solo registro. No hay diferencia de IO entre las dos consultas.

Para el caso 7, ambos realizarán un escaneo de tabla. No hay diferencia en el costo de IO.

Resumen: ¡Los casos 1-6 están hechos de victoria! Si estás en el Caso 7, entonces ya has perdido desde el punto de vista IO.

Puede medir IO utilizando el Analizador de consultas de SQL. Ejecuta esto antes de tu consulta.

SET STATISTICS IO ON 
8

Nadie mencionó IDENT_CURRENT ('Tabla 1') - a todos los golpes de distancia - por supuesto que sólo funciona en las columnas de identidad, pero que era la pregunta ...

+2

Votado, pero no * siempre * aplicable porque 'IDENT_CURRENT' no está necesariamente dentro del alcance. Para ser más rápido y más seguro, la transacción debe estar en un procedimiento almacenado y usar 'SCOPE_IDENTITY()' – Matthew