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)
char
vez devarchar
?select round(sysdate) from dual
e definitivamente precisamos disso no Sql Server.date
tipo de dados é mais rápida, conforme mostrado em meus testes acima.O SQL Server 2008 tem um novo tipo de dados de data e isso simplifica o problema para:
SELECT CAST(CAST(GETDATE() AS date) AS datetime)
fonte
DATEADD(DATEDIFF())
método para reduzir a parte do tempo lança uma exceção. Quandodatetime2
select cast(CAST(convert(datetime2(0), '0218-09-12', 120) AS date) as datetime2)
Itzik Ben-Gan em DATETIME Calculations, Part 1 (SQL Server Magazine, fevereiro de 2007) mostra três métodos de realizar essa conversão (do mais lento para o mais rápido ; a diferença entre o segundo e o terceiro método é pequena):
SELECT CAST(CONVERT(char(8), GETDATE(), 112) AS datetime) SELECT DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) SELECT CAST(CAST(GETDATE() - 0.50000004 AS int) AS datetime)
Sua técnica (casting to float ) é sugerida por um leitor na edição de abril da revista. Segundo ele, tem desempenho comparável ao da segunda técnica apresentada acima.
fonte
SELECT CAST(CAST(GETDATE() - '12:00:00.003' AS int) AS datetime)
, porque significa algo para mim e é muito mais fácil de lembrar.Convert(date, GetDate())
.Seu
CAST
-FLOOR
-CAST
já parece ser o caminho ideal, pelo menos no MS SQL Server 2005.Algumas outras soluções que vi têm uma conversão de string, como
Select Convert(varchar(11), getdate(),101)
nelas, que é mais lenta por um fator de 10.fonte
Tente por favor:
SELECT CONVERT(VARCHAR(10),[YOUR COLUMN NAME],105) [YOURTABLENAME]
fonte
SQL2005: Eu recomendo cast em vez de dateadd. Por exemplo,
select cast(DATEDIFF(DAY, 0, datetimefield) as datetime)
em média cerca de 10% mais rápido no meu conjunto de dados, do que
select DATEADD(DAY, DATEDIFF(DAY, 0, datetimefield), 0)
(e lançar em smalldatetime foi ainda mais rápido)
fonte