Qual método fornece o melhor desempenho ao remover a parte da hora de um campo de data e hora no SQL Server?
a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)
ou
b) select cast(convert(char(11), getdate(), 113) as datetime)
O segundo método envia mais alguns bytes de qualquer maneira, mas isso pode não ser tão importante quanto a velocidade da conversão.
Ambos também parecem ser muito rápidos, mas pode haver uma diferença de velocidade ao lidar com centenas de milhares ou mais de linhas?
Além disso, é possível que haja métodos ainda melhores para se livrar da parte do tempo de um datetime no SQL?
Respostas:
Estritamente, o método
a
é o menos intensivo em recursos:Comprovou menos uso de CPU para a mesma duração total de um milhão de linhas por alguém com tempo demais em suas mãos: A maneira mais eficiente no SQL Server para obter data a partir de data e hora?
Eu vi um teste semelhante em outro lugar com resultados semelhantes também.
Prefiro o DATEADD / DATEDIFF porque:
Exemplo: Por que minha expressão CASE não é determinística?
Editar, outubro de 2011
Para o SQL Server 2008+, você pode CAST para
date
ieCAST(getdate() AS date)
. Ou apenas use odate
tipo de dados para não ter tempo de remover.Editar, janeiro de 2012
Um exemplo prático de como isso é flexível: Precisa calcular por hora ou data arredondadas no sql server
Editar, maio de 2012
Não use isso nas cláusulas WHERE e similares sem pensar: adicionar uma função ou CAST a uma coluna invalida o uso do índice. Veja o número 2 aqui: http://www.simple-talk.com/sql/t-sql-programming/ten-common-sql-programming-mistakes/
Agora, isso tem um exemplo de versões posteriores do otimizador do SQL Server que gerenciam o CAST até a data corretamente, mas geralmente será uma má idéia ...
Editar, set 2018, para datetime2
fonte
DATE
horário dos dados é irritantemente restritivo no que permitirá que você faça com relação a dados como data, data e hora e interação com outros tipos de dados de data / hora. Para esses casos, aDATEADD()
abordagem reina.0218
vez de2018
como o ano e aDATEDIFF
parte de sua declaração gera uma exceçãoThe conversion of a datetime2 data type to a datetime data type resulted in an out-of-range datetime value
Tente:select DATEDIFF(dd, 0, convert(datetime2(0), '0218-09-12', 120))
SELECT DATEDIFF(dd, '19000101', convert(datetime2(0), '0218-09-12', 120))
No SQL Server 2008, você pode usar:
fonte
datetime
para adate
, e assim sua solução se resume a apenasCONVERT(DATE,getdate())
, o que já foi sugerido mais de uma vez.CAST(GETDATE() AS DATE)
ou estritamente ANSICAST(CURRENT_TIMESTAMP AS DATE)
que eu acho que é inútil. Fique com o primeiro.Claro que esse é um tópico antigo, mas para torná-lo completo.
No SQL 2008, você pode usar o tipo de dados DATE para fazer o seguinte:
fonte
... não é uma boa solução, de acordo com os comentários abaixo.
Eu excluiria esta resposta, mas a deixarei aqui como um contra-exemplo, pois acho que a explicação dos comentaristas sobre por que não é uma boa ideia ainda é útil.
fonte
No SQL Server 2008, há um tipo de dados DATE (também um tipo de dados TIME).
ou
fonte
Aqui está mais uma resposta, de outra pergunta duplicada:
Esse método de número mágico executa um pouco mais rápido que o método DATEADD. (Parece ~ 10%)
O tempo de CPU em várias rodadas de um milhão de registros:
Mas observe que esses números são possivelmente irrelevantes porque já são MUITO rápidos. A menos que eu tivesse conjuntos de registros de 100.000 ou mais, eu não conseguia nem obter o Tempo de CPU para ler acima de zero.
Considerando o fato de que o DateAdd se destina a essa finalidade e é mais robusto, eu diria que use o DateAdd.
fonte
'12:00:00.003'
que eu acho muito melhor, no entanto.fonte
Eu realmente gosto:
O
120
código de formato coagirá a data ao padrão ISO 8601:Super fácil de usar em dplyr (
R
) e pandas (Python
)!fonte
Cuidado!
O método a) eb) nem sempre tem a mesma saída!
Resultado:
2014-01-01 00:00:00.000
Resultado:
2013-12-31 00:00:00.000
(Testado no MS SQL Server 2005 e 2008 R2)
EDIT: De acordo com o comentário de Adam, isso não pode acontecer se você ler o valor da data da tabela, mas pode acontecer se você fornecer o valor da data como um literal (exemplo: como um parâmetro de um procedimento armazenado chamado via ADO.NET).
fonte
DATETIME
coluna. O mais alto disponível é .997 De: msdn.microsoft.com/en-us/library/ms187819.aspx, você verá que os valores são arredondados para ter o milésimo lugar em 0, 3 ou 7. O OP não verá o valor do seu teste em suas tabelas.Tire o tempo das inserções / atualizações em primeiro lugar. Quanto à conversão on-the-fly, nada pode superar uma função definida pelo usuário em termos de manutenção:
A implementação de
date_only
pode ser o que você quiser - agora é abstraída e o código de chamada é muito mais limpo.fonte
WHERE DateAdd(DateDiff(Column)) = @DateValue
não usará um índice. Por outro lado,WHERE Column >= dbo.UDF(@DateValue) AND Column < dbo.UDF(@DateValue + 1)
é SARGable. Portanto, tenha cuidado com o que você coloca.Veja esta pergunta:
Como posso truncar uma data e hora no SQL Server?
Faça o que fizer, não use o método string . Essa é a pior maneira de fazer isso.
fonte
Já respondi, mas vou jogar isso lá fora também ... isso supostamente também se forma bem, mas funciona jogando fora o decimal (que armazena tempo) do flutuador e retornando apenas uma parte inteira (que é a data)
segunda vez que encontrei esta solução ... peguei esse código
fonte
Este método não usa a função string.
Date
é basicamente um tipo de dados real com dígitos antes do decimal e fração do dia.acho que isso será mais rápido do que muito.
fonte
Para mim, o código abaixo é sempre um vencedor:
fonte
selecione CONVERT (char (10), GetDate (), 126)
fonte
Eu acho que você quer dizer
cast(floor(cast(getdate()as float))as datetime)
real é de apenas 32 bits e pode perder algumas informações
Isso é mais rápido
cast(cast(getdate()+x-0.5 as int)as datetime)
... embora apenas 10% mais rápido
(about 0.49 microseconds CPU vs. 0.58)
Isso foi recomendado e leva o mesmo tempo no meu teste agora:
DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)
No SQL 2008, a função SQL CLR é cerca de 5 vezes mais rápida do que o uso de uma função SQL, a 1,35 microssegundos versus 6,5 microsecções, indicando uma sobrecarga de chamada de função muito mais baixa para uma função CLR do SQL em comparação com uma simples UDF do SQL.
No SQL 2005, a função SQL CLR é 16 vezes mais rápida, por meu teste, em comparação com essa função lenta:
fonte
Que tal
select cast(cast my_datetime_field as date) as datetime)
? Isso resulta na mesma data, com o horário definido para 00:00, mas evita qualquer conversão em texto e também evita qualquer arredondamento numérico explícito.fonte
Eu acho que se você se mantiver estritamente com
TSQL
isso, esta é a maneira mais rápida de interromper o tempo:Eu achei esse método de truncamento cerca de 5% mais rápido que o
DateAdd
método. E isso pode ser facilmente modificado para arredondar para o dia mais próximo assim:fonte
Aqui, criei uma função para remover algumas partes de um datetime para o SQL Server. Uso:
create function dbo.uf_RoundDateTime(@dt as datetime, @part as char) returns datetime as begin if CHARINDEX( @part, 'smhd',0) = 0 return @dt; return cast( Case @part when 's' then convert(varchar(19), @dt, 126) when 'm' then convert(varchar(17), @dt, 126) + '00' when 'h' then convert(varchar(14), @dt, 126) + '00:00' when 'd' then convert(varchar(14), @dt, 112) end as datetime ) end
fonte
Caso alguém esteja procurando aqui uma versão do Sybase, pois várias das versões acima não funcionaram
fonte
cast
: No SQL Server 2008+, você pode CAST até o momento. Ou apenas use a data para que não haja tempo para remover.datetime
paradate
: nenhum deles possui um formato inerente.Se possível, para coisas especiais como essa, eu gosto de usar as funções CLR.
Nesse caso:
fonte
Pessoalmente, quase sempre uso funções definidas pelo usuário para isso se estiver lidando com o SQL Server 2005 (ou versão inferior), no entanto, deve-se notar que existem desvantagens específicas no uso de UDFs, especialmente se você for aplicá-las às cláusulas WHERE (veja abaixo e os comentários sobre esta resposta para obter mais detalhes). Se estiver usando o SQL Server 2008 (ou superior) - veja abaixo.
De fato, para a maioria dos bancos de dados criados, eu adiciono esses UDFs logo no início, pois sei que há uma chance de 99% de precisar deles mais cedo ou mais tarde.
Eu crio um para "somente data" e "somente horário" (embora o "somente data" seja de longe o mais usado dos dois).
Aqui estão alguns links para uma variedade de UDFs relacionadas à data:
Essencial SQL Server Data, hora e de data e hora Funções
Obter Data única função
Esse último link mostra nada menos que três maneiras diferentes de obter a data apenas como parte de um campo de data e hora e menciona alguns prós e contras de cada abordagem.
Se você estiver usando um UDF, deve-se observar que você deve evitar o uso do UDF como parte de uma cláusula WHERE em uma consulta, pois isso prejudicará bastante o desempenho da consulta. A principal razão para isso é que o uso de um UDF em uma cláusula WHERE torna essa cláusula não sargável , o que significa que o SQL Server não pode mais usar um índice com essa cláusula para melhorar a velocidade da execução da consulta. Com referência ao meu próprio uso de UDF, usarei frequentemente a coluna de data "bruta" na cláusula WHERE, mas aplicarei o UDF à coluna SELECTed. Dessa maneira, o UDF é aplicado apenas ao conjunto de resultados filtrado e nem a todas as linhas da tabela como parte do filtro.
Obviamente, a melhor abordagem absoluta para isso é usar o SQL Server 2008 (ou superior) e separar suas datas e horas , pois o mecanismo de banco de dados do SQL Server fornece nativamente os componentes individuais de data e hora e pode consultá-los de maneira eficiente. sem a necessidade de um UDF ou outro mecanismo para extrair a parte da data ou hora de um tipo de data e hora composto.
fonte
WHERE DateColumn >= {TimeTruncatingExpression}(@DateValue) AND DateColumn < {TimeTruncatingExpression}(@DateValue + 1)
. Eu senti que tinha que dizer alguma coisa, já que você disse que "quase sempre uso UDFs" não explica nenhuma das desvantagens, nem a maneira de fazer uma consulta SARGable apenas com data.Eu usaria:
Assim, criando efetivamente um novo campo a partir do campo de data que você já possui.
fonte
datetime
valor, convertê-los em seqüências de caracteres, concatená-los e, finalmente, converter o resultado novamentedatetime
é melhor do que, por exemplo, executar cálculos diretos no originaldatetime
(o métodoDATEADD
/DATEDIFF
)?MM
eDD
? Não existem funções no SQL Server.