Ho creato la tabella big_table secondo il tuo schema
create table big_table
(
updatetime datetime not null,
name char(14) not null,
TheData float,
primary key(Name,updatetime)
)
Ho quindi riempito la tabella con 50.000 righe con questo codice:
DECLARE @ROWNUM as bigint = 1
WHILE(1=1)
BEGIN
set @rownum = @ROWNUM + 1
insert into big_table values(getdate(),'name' + cast(@rownum as CHAR), cast(@rownum as float))
if @ROWNUM > 50000
BREAK;
END
Utilizzando SSMS, ho quindi testato entrambe le query e mi sono reso conto che nella prima query stai cercando il MAX di TheData e nel secondo, il MAX di updatetime
Ho quindi modificato la prima query per ottenere anche il massimo di updatetime
set statistics time on -- execution time
set statistics io on -- io stats (how many pages read, temp tables)
-- query 1
SELECT MAX([UpdateTime])
FROM big_table
-- query 2
SELECT MAX([UpdateTime]) AS value
from
(
SELECT [UpdateTime]
FROM big_table
group by [UpdateTime]
) as t
set statistics time off
set statistics io off
Usando il tempo delle statistiche ottengo il numero di millisecondi necessari per analizzare, compilare ed eseguire ogni istruzione
Utilizzando Statistics IO ottengo informazioni sull'attività del disco
STATISTICS TIME e STATISTICS IO forniscono informazioni utili. Come ad esempio le tabelle temporanee utilizzate (indicate dal tavolo di lavoro). Inoltre, quante pagine logiche sono state lette, il che indica il numero di pagine del database lette dalla cache.
Quindi attivo il piano di esecuzione con CTRL + M (attiva mostra il piano di esecuzione effettivo) e quindi eseguo con F5.
Ciò fornirà un confronto di entrambe le query.
Ecco l'output della scheda Messaggi
- Query 1
Tabella 'big_table'. Conteggio scansioni 1, letture logiche 543 , letture fisiche 0, letture read-ahead 0, letture log lob 0, letture fisiche lob 0, letture read lob 0.
Tempi di esecuzione di SQL Server:
tempo CPU = 16 ms, tempo trascorso = 6 ms .
- Query 2
Tabella " Tavolo da lavoro ". Conteggio scansioni 0, letture logiche 0, letture fisiche 0, letture read-ahead 0, letture logiche lob 0, letture fisiche lob 0, letture read lob 0.
Tabella 'big_table'. Conteggio scansioni 1, letture logiche 543 , letture fisiche 0, letture read-ahead 0, letture log lob 0, letture fisiche lob 0, letture read lob 0.
Tempi di esecuzione di SQL Server:
tempo CPU = 0 ms, tempo trascorso = 35 ms .
Entrambe le query generano 543 letture logiche, ma la seconda query ha un tempo trascorso di 35 ms, mentre la prima ha solo 6 ms. Noterai anche che la seconda query comporta l'uso di tabelle temporanee in tempdb, indicato dalla parola worktable . Anche se tutti i valori per worktable sono a 0, il lavoro è stato ancora svolto in tempdb.
Quindi c'è l'output dalla scheda del piano di esecuzione effettivo accanto alla scheda Messaggi
Secondo il piano di esecuzione fornito da MSSQL, la seconda query fornita ha un costo batch totale del 64%, mentre la prima costa solo il 36% del batch totale, quindi la prima query richiede meno lavoro.
Usando SSMS, puoi testare e confrontare le tue query e scoprire esattamente come MSSQL sta analizzando le tue query e quali oggetti: tabelle, indici e / o statistiche se ne vengono utilizzati per soddisfare tali query.
Una nota a margine aggiuntiva da tenere a mente durante il test è la pulizia della cache prima del test, se possibile. Questo aiuta a garantire che i confronti siano accurati e questo è importante quando si pensa all'attività del disco. Comincio con DBCC DROPCLEANBUFFERS e DBCC FREEPROCCACHE per cancellare tutta la cache. Fare attenzione, tuttavia, a non utilizzare questi comandi su un server di produzione effettivamente in uso, poiché si forzerà efficacemente il server a leggere tutto dal disco alla memoria.
Ecco la documentazione pertinente.
- Svuota la cache del piano con DBCC FREEPROCCACHE
- Cancella tutto dal pool di buffer con DBCC DROPCLEANBUFFERS
L'uso di questi comandi potrebbe non essere possibile a seconda dell'utilizzo dell'ambiente.
Aggiornato il 28/10 12:46
Correzioni all'immagine del piano di esecuzione e all'output delle statistiche.
getdate()
uscire dal giro