SQL Server 2008 e superior
No SQL Server 2008 e superior, é claro que a maneira mais rápida é Convert(date, @date)
. Isso pode ser convertido de volta para um datetime
ou datetime2
se necessário.
O que é realmente melhor no SQL Server 2005 e anteriores?
Tenho visto afirmações inconsistentes sobre o que é mais rápido para truncar o tempo de uma data no SQL Server, e algumas pessoas até disseram que fizeram testes, mas minha experiência tem sido diferente. Então, vamos fazer alguns testes mais rigorosos e deixar que todos tenham o script para que, se eu cometer algum erro, as pessoas possam me corrigir.
As conversões flutuantes não são precisas
Primeiro, eu evitaria a conversão datetime
para float
, porque ele não converte corretamente. Você pode se safar fazendo a coisa de remoção de tempo com precisão, mas acho uma má ideia usá-lo porque comunica implicitamente aos desenvolvedores que esta é uma operação segura e não é . Dê uma olhada:
declare @d datetime;
set @d = '2010-09-12 00:00:00.003';
select Convert(datetime, Convert(float, @d));
Isso não é algo que deveríamos ensinar às pessoas em nosso código ou em nossos exemplos online.
Além disso, não é a maneira mais rápida!
Prova - Teste de Desempenho
Se você deseja realizar alguns testes para ver como os diferentes métodos realmente se acumulam, você precisará deste script de configuração para executar os testes mais adiante:
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;
Observe que isso cria uma tabela de 427,57 MB em seu banco de dados e levará cerca de 15-30 minutos para ser executado. Se seu banco de dados for pequeno e definido para 10% de crescimento, demorará mais do que se você dimensionar primeiro o suficiente.
Agora, para o script de teste de desempenho real. Observe que é útil não retornar linhas de volta ao cliente, pois isso é extremamente caro em 26 milhões de linhas e ocultaria as diferenças de desempenho entre os métodos.
Resultados de Desempenho
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;
Algumas análises errantes
Algumas notas sobre isso. Em primeiro lugar, se apenas executar um GROUP BY ou uma comparação, não há necessidade de converter de volta para datetime
. Portanto, você pode economizar um pouco de CPU evitando isso, a menos que precise do valor final para fins de exibição. Você pode até mesmo GROUP BY o valor não convertido e colocar a conversão apenas na cláusula 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)
Além disso, veja como as conversões numéricas levam apenas um pouco mais de tempo para serem convertidas datetime
, mas a varchar
conversão quase dobra? Isso revela a parte da CPU que é dedicada ao cálculo da data nas consultas. Existem partes do uso da CPU que não envolvem cálculo de data e isso parece ser algo próximo a 19875 ms nas consultas acima. Em seguida, a conversão leva algum valor adicional, portanto, se houver duas conversões, esse valor é usado cerca de duas vezes.
Um exame mais revela que comparada a Convert(, 112)
, a Convert(, 101)
consulta tem algum gasto adicional de CPU (já que usa um mais longo varchar
?), Porque a segunda conversão de volta para date
não custa tanto quanto a conversão inicial para varchar
, mas com Convert(, 112)
ela está mais perto do mesmo 20000 Custo base de CPU de ms.
Aqui estão os cálculos do tempo de CPU que usei para a análise acima:
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 é o tempo de CPU para uma viagem de ida e volta para datetime
.
single é o tempo de CPU para uma única conversão para o tipo de dados alternativo (aquele que tem o efeito colateral de remover a parte do tempo).
de base é o cálculo de subtraindo single
a diferença entre as duas invocações: single - (round - single)
. É um valor aproximado que assume a conversão de e para esse tipo de dados e datetime
é aproximadamente o mesmo em ambas as direções. Parece que essa suposição não é perfeita, mas está próxima porque os valores estão todos próximos a 20000 ms, com apenas uma exceção.
Outra coisa interessante é que o custo base é quase igual ao Convert(date)
método único (que deve ser quase custo 0, pois o servidor pode extrair internamente a parte do dia inteiro diretamente dos primeiros quatro bytes do datetime
tipo de dados).
Conclusão
Portanto, o que parece é que o varchar
método de conversão de direção única leva cerca de 1,8 μs e o DateDiff
método de direção única leva cerca de 0,18 μs. Estou baseando isso no tempo de "CPU base" mais conservador em meu teste de 18458 ms no total para 25.920.000 linhas, então 23218 ms / 25920000 = 0,18 μs. A aparente melhoria de 10x parece muito, mas é francamente muito pequena até que você esteja lidando com centenas de milhares de linhas (617 mil linhas = economia de 1 segundo).
Mesmo com essa pequena melhoria absoluta, na minha opinião, o DateAdd
método ganha porque é a melhor combinação de desempenho e clareza. A resposta que exige um "número mágico" de 0.50000004
vai morder alguém algum dia (cinco zeros ou seis ???), além de ser mais difícil de entender.
Notas Adicionais
Quando eu tiver algum tempo, vou mudar 0.50000004
para '12:00:00.003'
e ver como fica. É convertido para o mesmo datetime
valor e acho muito mais fácil de lembrar.
Para os interessados, os testes acima foram executados em um servidor onde @@ Version retorna o seguinte:
Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) 9 de julho de 2008 14:43:34 Copyright (c) 1988-2008 Microsoft Corporation Standard Edition no Windows NT 5.2 (Build 3790: Service Pack 2)