SQL Server 2008 e versioni successive
In SQL Server 2008 e versioni successive, ovviamente, il modo più veloce è Convert(date, @date)
. Questo può essere restituito a un datetime
o datetime2
se necessario.
Cosa c'è di veramente migliore in SQL Server 2005 e versioni precedenti?
Ho visto affermazioni incoerenti su ciò che è più veloce per troncare l'ora da una data in SQL Server e alcune persone hanno persino affermato di aver eseguito dei test, ma la mia esperienza è stata diversa. Quindi facciamo dei test più rigorosi e lasciamo che tutti abbiano la sceneggiatura, così se faccio degli errori le persone possono correggermi.
Le conversioni flottanti non sono accurate
Innanzitutto, starei lontano dalla conversione datetime
in float
, perché non si converte correttamente. Potresti cavartela facendo la cosa della rimozione del tempo in modo accurato, ma penso che sia una cattiva idea usarla perché comunica implicitamente agli sviluppatori che questa è un'operazione sicura e non lo è . Guarda:
declare @d datetime;
set @d = '2010-09-12 00:00:00.003';
select Convert(datetime, Convert(float, @d));
Questo non è qualcosa che dovremmo insegnare alle persone nel nostro codice o nei nostri esempi online.
Inoltre, non è nemmeno il modo più veloce!
Prova - Test delle prestazioni
Se vuoi eseguire tu stesso alcuni test per vedere come i diversi metodi si accumulano, allora avrai bisogno di questo script di installazione per eseguire i test più in basso:
create table AllDay (Tm datetime NOT NULL CONSTRAINT PK_AllDay PRIMARY KEY CLUSTERED);
declare @d datetime;
set @d = DateDiff(Day, 0, GetDate());
insert AllDay select @d;
while @@ROWCOUNT != 0
insert AllDay
select * from (
select Tm =
DateAdd(ms, (select Max(DateDiff(ms, @d, Tm)) from AllDay) + 3, Tm)
from AllDay
) X
where Tm < DateAdd(Day, 1, @d);
exec sp_spaceused AllDay;
Tieni presente che questo crea una tabella da 427,57 MB nel tuo database e richiederà qualcosa come 15-30 minuti per l'esecuzione. Se il database è piccolo e impostato su una crescita del 10%, ci vorrà più tempo rispetto a quando si dimensiona prima abbastanza grande.
Passiamo ora allo script di test delle prestazioni effettivo. Si noti che è utile non restituire le righe al client poiché questo è incredibilmente costoso su 26 milioni di righe e nasconderebbe le differenze di prestazioni tra i metodi.
Risultati delle prestazioni
set statistics time on;
GO
declare
@dd date,
@d datetime,
@di int,
@df float,
@dv varchar(10);
select @d = CONVERT(date, Tm) from AllDay;
select @d = CAST(Tm - 0.50000004 AS int) from AllDay;
select @d = DATEDIFF(DAY, 0, Tm) from AllDay;
select @d = FLOOR(CAST(Tm as float)) from AllDay;
select @d = CONVERT(VARCHAR(8), Tm, 112) from AllDay;
select @d = CONVERT(CHAR(8), Tm, 112) from AllDay;
select @d = CONVERT(VARCHAR(10), Tm, 101) from AllDay;
select @dd = Tm from AllDay;
select @di = CAST(Tm - 0.50000004 AS int) from AllDay;
select @di = DATEDIFF(DAY, 0, Tm) from AllDay;
select @df = FLOOR(CAST(Tm as float)) from AllDay;
select @dv = CONVERT(VARCHAR(8), Tm, 112) from AllDay;
select @dv = CONVERT(CHAR(8), Tm, 112) from AllDay;
select @dv = CONVERT(VARCHAR(10), Tm, 101) from AllDay;
GO
set statistics time off;
Alcune analisi vaganti
Alcune note su questo. Prima di tutto, se si esegue solo un GROUP BY o un confronto, non è necessario riconvertirsi a datetime
. Quindi puoi risparmiare un po 'di CPU evitandolo, a meno che tu non abbia bisogno del valore finale per scopi di visualizzazione. Puoi anche GROUP BY il valore non convertito e inserire la conversione solo nella clausola SELECT:
select Convert(datetime, DateDiff(dd, 0, Tm))
from (select '2010-09-12 00:00:00.003') X (Tm)
group by DateDiff(dd, 0, Tm)
Inoltre, vedi come le conversioni numeriche impiegano solo un po 'più di tempo per riconvertirsi datetime
, ma la varchar
conversione quasi raddoppia? Questo rivela la parte della CPU dedicata al calcolo della data nelle query. Ci sono parti dell'utilizzo della CPU che non implicano il calcolo della data e questo sembra essere qualcosa di vicino a 19875 ms nelle query precedenti. Quindi la conversione richiede un importo aggiuntivo, quindi se ci sono due conversioni, tale importo viene utilizzato circa il doppio.
Un esame più approfondito rivela che rispetto a Convert(, 112)
, la Convert(, 101)
query ha qualche spesa aggiuntiva per la CPU (dato che usa un più lungo varchar
?), Perché la seconda conversione a date
non costa quanto la conversione iniziale a varchar
, ma con Convert(, 112)
essa è più vicina allo stesso 20000 ms costo base della CPU.
Ecco quei calcoli sul tempo della CPU che ho usato per l'analisi sopra:
method round single base
date 21324 19891 18458
int 23031 21453 19875
datediff 23782 23218 22654
float 36891 29312 21733
varchar-112 102984 64016 25048
varchar-101 123375 65609 7843
round è il tempo della CPU per un viaggio di andata e ritorno a datetime
.
single è il tempo della CPU per una singola conversione nel tipo di dati alternativo (quello che ha l'effetto collaterale di rimuovere la porzione di tempo).
di base è il calcolo della sottraendo single
la differenza tra le due invocazioni: single - (round - single)
. È una cifra datetime
approssimativa che presuppone la conversione da e verso quel tipo di dati ed è approssimativamente uguale in entrambe le direzioni. Sembra che questa ipotesi non sia perfetta ma è vicina perché i valori sono tutti vicini a 20000 ms con una sola eccezione.
Un'altra cosa interessante è che il costo di base è quasi uguale al Convert(date)
metodo singolo (che deve essere quasi pari a 0, poiché il server può estrarre internamente la parte intera del giorno dai primi quattro byte del datetime
tipo di dati).
Conclusione
Quindi quello che sembra è che il varchar
metodo di conversione unidirezionale impiega circa 1,8 μs e il DateDiff
metodo unidirezionale impiega circa 0,18 μs. Sto basando questo sul tempo di "CPU di base" più conservativo nei miei test di 18458 ms totali per 25.920.000 righe, quindi 23218 ms / 25920000 = 0,18 μs. L'apparente miglioramento di 10 volte sembra molto, ma francamente è piuttosto piccolo finché non si ha a che fare con centinaia di migliaia di righe (617.000 righe = 1 secondo di risparmio).
Anche dato questo piccolo miglioramento assoluto, secondo me, il DateAdd
metodo vince perché è il miglior connubio tra performance e chiarezza. La risposta che richiede un "numero magico" 0.50000004
morderà qualcuno un giorno (cinque zeri o sei ???), in più è più difficile da capire.
Note aggiuntive
Quando ricevo un po 'di tempo ho intenzione di cambiare 0.50000004
a '12:00:00.003'
e vedere come lo fa. Viene convertito allo stesso datetime
valore e lo trovo molto più facile da ricordare.
Per chi fosse interessato, i test di cui sopra sono stati eseguiti su un server dove @@ Version restituisce quanto segue:
Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) 9 luglio 2008 14:43:34 Copyright (c) 1988-2008 Microsoft Corporation Standard Edition su Windows NT 5.2 (Build 3790: Service Pack 2)