2009-02-26 9 views
16

Desidero trovare il valore AutoIncrementato più alto da un campo. (non viene recuperato dopo un inserto in cui è possibile utilizzare @@SCOPE_IDENTITY ecc.) Quale di queste due query dovrebbe essere più veloce o offrire prestazioni migliori. Id è la chiave primaria e il campo autoincrement per Table1. E questo è per SQL Server 2005.Per i campi di autoincremento: MAX (ID) vs TOP 1 ID ORDINE PER ID DESC

SELECT MAX(Id) FROM Table1 

SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC 

[Edit]
Sì, in questo caso Id è il campo su cui ho definito l'indice cluster.
Se l'indice è ID DESC, quindi cosa ...
E sì, sarebbe bello sapere come la prestazione sarebbe interessata se
1. Id è un indice cluster + chiave primaria.
2. Id è un indice cluster e non una chiave primaria.
3. Id è un indice ASC + chiave primaria non cluster.
4. Id è un indice ASC non cluster e non una chiave primaria.
5. Id è un indice non cluster DESC + chiave primaria.
6. Id è un indice DESC non cluster e non chiave primaria.
7. Id è solo AutoIncrement

Spero che non sia un ordine troppo alto!

+0

Dalle risposte qui, con la indice non c'è differenza nelle prestazioni. Comunque ho trovato 'MAX' /' MIN' ha un paio di vantaggi. Innanzitutto, come indicato di seguito senza un indice "MAX", sarà più performante, anche questo diventa significativo quando si hanno giunzioni più complesse. In secondo luogo se ci sono valori NULL allora 'SELECT MIN' restituisce un valore ma' SELECT TOP 1 ... ASC' restituisce 'NULL' – icc97

risposta

7

In teoria, useranno gli stessi piani e correranno quasi contemporaneamente.

In pratica,

SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC 

sarà più probabilmente usare un PRIMARY KEY INDEX.

Inoltre, questo è più estendibile se si decide di selezionare un'altra colonna insieme a id.

Un vero e proprio piano sulla MAX() dice:

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

, mentre piano per TOP 1 dice:

SELECT <- TOP <- CLUSTERED INDEX SCAN 

, i. e. aggregate è stato omesso.

Aggregato in realtà non farà nulla qui, in quanto vi è una sola riga.

PS Come @Mehrdad Afshari e @John Sansom notato, su un campo non indicizzato MAX è leggermente più veloce (naturalmente, non 20 volte ottimizzatore dice):

 
-- 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 è deterministico. Come mai qualcosa "più probabilmente" userà un indice? –

+0

Le decisioni dell'ottimizzatore dipendono dalle statistiche della tabella che dipendono dai dati della tabella che sono probabilistici. Un ottimizzatore può decidere di ordinare la tabella anziché utilizzare INDICE SCAN insieme a TOP. – Quassnoi

+0

Sono in ritardo al party, ma non so qual è l'efficienza della memoria dei due piani per uno scenario di campo indicizzato? Se abbiamo la stessa query in esecuzione un numero enorme di volte, qualsiasi piano richiederà un buffer più alto perderà. – vk239

3

confrontare Basta piani di esecuzione e vedrete (premere Ctrl+M in Management Studio quando si modifica una query). La mia ipotesi è che queste query siano ugualmente performanti a patto che ci sia un indice (in cluster) sulla colonna Id.

Tuttavia, questo nel suo complesso è un molto male idea.

+0

Qual è una pessima idea? – Learning

+0

L'utilizzo di query aggiuntive per recuperare l'ID di una riga appena aggiunta è una pessima idea. Tra queste due richieste potrebbero verificarsi molte operazioni di database. –

+0

Oh davvero. Abbastanza vero. +1 – Learning

2

MAX è generalmente più veloce.

Entrambe le query utilizzeranno l'indice sulla colonna, se esistente.

Se nessun indice esiste sulla colonna, la query TOP 1 userà un operatore Top N Sort per sorta tabella anziché flusso aggregazione, che lo rende più lento.

MAX fornisce anche una migliore leggibilità.

laterale Nota: mentre MAX userà un operatore di flusso aggregato nel piano di esecuzione nel caso indicizzato, non ha alcun costo specifico, è solo elaborazione di una singola fila (Actual Rows = 1). È possibile confrontare le query eseguendole in un singolo batch e vedere il costo relativo. Nel caso indicizzato, entrambe le query costeranno il 50%. Ho testato il caso non indicizzato su un tavolo con circa 7000 righe e TOP costerà il 65% rispetto a MAX che costa il 35%.

+0

TOP 1 non ordinerà la query. La domanda nota esplicitamente che ID è una CHIAVE PRIMARIA. – Quassnoi

+0

E penso di aver menzionato esplicitamente "se nessun indice esiste sulla colonna". Leggi più attentamente. –

+0

Un indice esiste sempre su una chiave primaria. – Quassnoi

9

Se esiste un indice cluster, non vi sono praticamente differenze di prestazioni tra le due query.

Questo è perché entrambi eseguiranno una scansione indice clusterizzata che sosterrà il 100% del costo della query.

L'esecuzione delle due query su una colonna che non ha un indice comporta l'utilizzo di 3 operatori in entrambi i piani di esecuzione.

La clausola Top utilizza l'operatore Sort e la funzione Max utilizza un operatore Stream Aggregate.

Quando non c'è indice, la funzione MAX() offre prestazioni migliori.

Proof of concept può essere trovato e completa procedura dettagliata di uno scenario di test può essere trovato here

Performance Comparison Top 1 Verses MAX() Funciton

+0

il caso indicizzato, l'operatore di flusso di aggregazione avrà "Righe reali = 1" che sostanzialmente non costa nulla. Se non si dispone di un indice, il piano di esecuzione per TOP 1 avrà un ordinamento "Top N" che lo renderà più lento rispetto a "Stream Aggregate" utilizzato da MAX. –

+0

@Mehrdad: Effettivamente, i dettagli completi verranno aggiunti al mio blog. –

+0

@John, usa il link permanente a questa domanda sul tuo blog http://stackoverflow.com/questions/590079/ –

2

Ho appena testato le due istruzioni SQL che hai fornito contro un tipico set di dati:

SELECT MAX(Id) FROM Table1 

SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC 

E SELECT TOP 1 Id FROM Table1 ORDER BY Id DESC è leggermente più veloce perché ha un ultimo passaggio nel piano di esecuzione. Qui ci sono i piani di esecuzione ogni query svolge:

SELEZIONE MAX (Id) FROM Table1

Clustered Index Scan >> >> Top flusso aggregato >> Selezionare

SELEZIONE TOP 1 Id DA Tabella 1 Ordina per ID DESC

Clustered Index Scan >> su >> Selezionare

1

Sì in questo caso Id è il campo che ho definito l'indice in cluster. Se l'indice è ID DESC allora cosa ..E sì che sarebbe bello sapere come la performance sarebbe colpiti se

  1. Id è un indice cluster + chiave primaria.
  2. L'ID è un indice cluster e non una chiave primaria.
  3. Id è un indice ASC + chiave primaria non cluster.
  4. ID è un indice ASC non cluster e non chiave primaria.
  5. ID è un indice non cluster DESC + chiave primaria.
  6. Id è un indice DESC non cluster e non chiave primaria.
  7. Id è solo AutoIncrement

per i casi 1 e 2, sia eseguirà una scansione indice cluster che restituisce un singolo record. Non c'è nessuna differenza tra le due query.

Per i casi 3, 4, 5 e 6, entrambi eseguiranno una scansione dell'indice che restituisce un singolo record. Non c'è nessuna differenza tra le due query.

Per il caso 7, entrambi eseguiranno una scansione della tabella. Non c'è differenza nel costo dell'IO.

Riepilogo: I casi 1-6 sono fatti di vincita! Se ti trovi in ​​Case 7, hai già perso da un punto di vista dell'IO.

È possibile misurare l'I/O utilizzando l'analizzatore Query di SQL. Esegui questo prima della tua richiesta.

SET STATISTICS IO ON 
8

nessuno ha menzionato IDENT_CURRENT ('Tabella 1') - li spazza via - ovviamente funziona solo su colonne di identità, ma che era la domanda ...

+2

Votato, ma non * sempre * applicabile perché 'IDENT_CURRENT' non è necessariamente nell'ambito. Per essere il più veloce e sicuro, la transazione dovrebbe essere in una stored procedure e usare 'SCOPE_IDENTITY()' – Matthew