DateTime2 vs DateTime no SQL Server
-
20-09-2019 - |
Pergunta
Qual deles:
é o maneira recomendada de armazenar data e hora no SQL Server 2008+?
Estou ciente das diferenças de precisão (e provavelmente de espaço de armazenamento), mas ignorando-as por enquanto, existe um documento de práticas recomendadas sobre quando usar o quê, ou talvez devêssemos apenas usar datetime2
apenas?
Solução
A documentação do MSDN para data hora recomenda usar DateTime2. Aqui está a recomendação deles:
Use o
time
,date
,datetime2
edatetimeoffset
Tipos de dados para novo trabalho. Esses tipos estão alinhados com o padrão SQL. Eles são mais portáteis.time
,datetime2
edatetimeoffset
Forneça mais segundos precisão.datetimeoffset
Fornece suporte de fuso horário para aplicativos implantados globalmente.
O DateTime2 possui um intervalo de data maior, uma precisão fracionária padrão maior e precisão opcional especificada pelo usuário. Também dependendo da precisão especificada pelo usuário, ele pode usar menos armazenamento.
Outras dicas
DATETIME2
tem um intervalo de data de "0001 /01 /01" através "9999/21/11" enquanto o DATETIME
O tipo suporta apenas o ano de 1753-9999.
Além disso, se você precisar, DATETIME2
pode ser mais preciso em termos de tempo; DateTime é limitado a 3 1/3 milissegundos, enquanto DATETIME2
pode ser preciso até 100ns.
Ambos os tipos mapeiam para System.DateTime
em .net - nenhuma diferença lá.
Se você tiver a escolha, eu recomendaria usar DATETIME2
quando possível. Eu não vejo nenhum benefício usando DATETIME
(Exceto para compatibilidade com versões anteriores) - você terá menos problemas (com as datas fora de alcance e complicações assim).
Além disso: se você precisar apenas da data (sem parte do tempo), use a data - é tão bom quanto DATETIME2
E economiza seu espaço também! :-) O mesmo vale apenas para o tempo - use TIME
. É para isso que esses tipos existem!
DateTime2 vence na maioria dos aspectos, exceto (compatibilidade antiga de aplicativos)
- maior faixa de valores
- Melhor Precisão
- menor espaço de armazenamento (Se a precisão opcional especificada pelo usuário for especificada)
Observe os seguintes pontos
- Sintaxe
- DATETIME2 [(Secondos fracionários Precision => Olhe abaixo do tamanho do armazenamento)]
- Precisão, escala
- 0 a 7 dígitos, com precisão de 100ns.
- A precisão padrão é de 7 dígitos.
- Tamanho de armazenamento
- 6 bytes para precisão menor que 3;
- 7 bytes para precisão 3 e 4.
- Toda a outra precisão requer 8 bytes.
- DateTime2 (3) Tenha o mesmo número de dígitos que o DateTime, mas usa 7 bytes de armazenamento em vez de 8 byte (SQLHINTS- DateTime vs DateTime2)
- Encontre mais DateTime2 (artigo do transact-sql msdn)
Fonte da imagem:Kit de treinamento com ritmo próprio do MCTS (Exame 70-432): Microsoft® SQL Server® 2008-Implementação e manutençãoCapítulo 3: Tabelas -> Lição 1: Criando tabelas -> Página 66
Eu concorrer com @marc_s e @adam_poward - DateTime2 é o método preferido no futuro. Possui uma faixa mais ampla de datas, maior precisão e usa armazenamento igual ou menos (dependendo da precisão).
Uma coisa que a discussão perdeu, no entanto ...
@Marc_s estados: Both types map to System.DateTime in .NET - no difference there
. Isto está certo, No entanto, o inverso não é verdadeiro... e isso importa ao fazer pesquisas de intervalo (por exemplo, "Encontre -me todos os registros modificados em 5/5/2010").
Versão do .NET de Datetime
tem alcance semelhante e precisão a DateTime2
. Ao mapear um .net Datetime
até o velho SQL DateTime
um O arredondamento implícito ocorre. O velho sql DateTime
é preciso para 3 milissegundos. Isso significa que 11:59:59.997
é o mais próximo possível do final do dia. Qualquer coisa mais alta é arredondada para o dia seguinte.
Experimente isso:
declare @d1 datetime = '5/5/2010 23:59:59.999'
declare @d2 datetime2 = '5/5/2010 23:59:59.999'
declare @d3 datetime = '5/5/2010 23:59:59.997'
select @d1 as 'IAmMay6BecauseOfRounding', @d2 'May5', @d3 'StillMay5Because2msEarlier'
Evitar esse arredondamento implícito é um motivo significativo para passar para o DateTime2. O arredondamento implícito de datas causa claramente a confusão:
- Strange DateTime Behavior no SQL Server
- http://bytes.com/topic/sql-sherver/answers/578416-warird-millisecond-part-dateteime-data-sql-sever-2000-a
- SQL Server 2008 e milissegundos
- http://improve.dk/archive/2011/06/16/getting-bit-datetime-unding-or-why-235959-999-ltgt.aspx
- http://milesquaretech.com/blog/post/2011/09/12/datetime-vs-datetime2-sql-is-roding-my-999-milisseconds!.aspx
Quase todas as respostas e comentários foram pesados nos prós e leves nos contras.Aqui está uma recapitulação de todos os prós e contras até agora, além de alguns contras cruciais (no item 2 abaixo) que só vi mencionados uma vez ou nunca vi.
- PRÓS:
1.1.Mais compatível com ISO (ISO 8601) (embora eu não saiba como isso funciona na prática).
1.2.Mais alcance (1/1/0001 a 31/12/9999 vs.1/1/1753-31/12/9999) (embora o intervalo extra, todos anteriores ao ano 1753, provavelmente não será usado, exceto por ex., em dados históricos, astronômicos, geológicos, etc.aplicativos).
1.3.Corresponde exatamente à gama de .NET DateTime
O intervalo do tipo (embora ambos sejam convertidos sem codificação especial se os valores estiverem dentro do intervalo e da precisão do tipo de destino, exceto para Con # 2.1 abaixo, caso contrário ocorrerá erro/arredondamento).
1.4.Mais precisão (100 nanossegundos, também conhecido como 0,000.000,1 seg.vs.3,33 milissegundos, também conhecido como 0,003,33 seg.) (embora a precisão extra provavelmente não seja usada, exceto por exemplo, em aplicativos de engenharia/científicos).
1.5.Quando configurado para semelhante (como em 1 milissegundo não é "o mesmo" (como em 3,33 milissegundos) como Iman Abidi afirmou) precisão como DateTime
, usa menos espaço (7 vs.8 bytes), mas é claro que você estaria perdendo o benefício de precisão, que é provavelmente um dos dois (o outro sendo o intervalo) mais elogiado, embora provavelmente benefícios desnecessários).
- CONTRAS:
2.1.Ao passar um parâmetro para um .NET SqlCommand
, você deve especificar System.Data.SqlDbType.DateTime2
se você estiver passando um valor fora do SQL Server DateTime
intervalo e/ou precisão de , porque o padrão é System.Data.SqlDbType.DateTime
.
2.2.Não pode ser convertido implícita/facilmente em um valor numérico de ponto flutuante (número de dias desde a data e hora mínima) para fazer o seguinte para/com ele em expressões do SQL Server usando valores numéricos e operadores:
2.2.1.adicione ou subtraia o número de dias ou dias parciais.Observação:Usando DateAdd
A função como solução alternativa não é trivial quando você precisa considerar várias, se não todas, partes da data e hora.
2.2.2.pegue a diferença entre duas datas e horas para fins de cálculo de “idade”.Observação:Você não pode simplesmente usar o SQL Server DateDiff
Função em vez disso, porque não calcula age
como a maioria das pessoas esperaria, se as duas datas e horas cruzarem o limite de data e hora do calendário/relógio das unidades especificadas, mesmo que seja para uma pequena fração dessa unidade, ele retornará a diferença como 1 dessa unidade vs. .0.Por exemplo, o DateDiff
em Day
’s de duas datas com apenas 1 milissegundo de intervalo retornarão 1 vs.0 (dias) se essas datas estiverem em dias corridos diferentes (ou seja,“1999-12-31 23:59:59.9999999” e “2000-01-01 00:00:00.0000000”).A mesma diferença de data e hora de 1 milissegundo, se movida para que não ultrapassem um dia do calendário, retornará um “DateDiff” em Day
de 0 (dias).
2.2.3.levar a Avg
de datas e horas (em uma consulta agregada), simplesmente convertendo primeiro para “Float” e depois novamente para DateTime
.
OBSERVAÇÃO:Converter DateTime2
para um valor numérico, você terá que fazer algo como a fórmula a seguir, que ainda assume que seus valores não são inferiores ao ano de 1970 (o que significa que você está perdendo todo o intervalo extra mais outros 217 anos.Observação:Talvez você não consiga simplesmente ajustar a fórmula para permitir um intervalo extra, pois pode encontrar problemas de estouro numérico.
25567 + (DATEDIFF(SECOND, {d '1970-01-01'}, @Time) + DATEPART(nanosecond, @Time) / 1.0E + 9) / 86400.0
- Fonte:“ https://siderite.blogspot.com/2015/08/how-to-translate-t-sql-datetime2-to.html “
Claro, você também pode Cast
para DateTime
primeiro (e se necessário de volta novamente para DateTime2
), mas você perderia os benefícios de precisão e alcance (todos anteriores ao ano 1753) de DateTime2
vs. DateTime
que são provavelmente os 2 maiores e também, ao mesmo tempo, provavelmente os 2 menos necessários, o que levanta a questão: por que usá-lo quando você perde as conversões implícitas/fáceis para números de ponto flutuante (nº de dias) para adição/subtração/"idade " (v. DateDiff
) / Avg
benefício de cálculo, que é um grande problema na minha experiência.
Aliás, o Avg
de data-hora é (ou pelo menos deve ser) um caso de uso importante.a) Além de ser usado para obter a duração média quando datas e horas (desde uma data e hora base comum) são usadas para representar a duração (uma prática comum), b) também é útil obter uma estatística do tipo painel sobre qual é a data média. a hora está na coluna data-hora de um intervalo/grupo de linhas.c) Um padrão (ou pelo menos deve ser padrão) A consulta ad-hoc para monitorar/solucionar problemas de valores em uma coluna que pode não ser mais válida/por mais tempo e/ou pode precisar ser obsoleta é listar para cada valor a contagem de ocorrências e (se disponível) o Min
, Avg
e Max
carimbos de data e hora associados a esse valor.
O DateTime2 causa estragos se você é um desenvolvedor de acesso tentando escrever agora () no campo em questão. Acabei de fazer um acesso -> SQL 2008 R2 Migration e colocou todos os campos DateTime como DateTime2. Anexando um registro com agora () conforme o valor bombardeado. Tudo bem em 1/1/2012 14:53:04, mas não em 1/10/2012 14:53:04.
Uma vez que o personagem fez a diferença. Espero que ajude alguém.
Aqui está um exemplo que mostrará as diferenças no tamanho do armazenamento (bytes) e precisão entre o tempo pequeno, DateTime, DateTime2 (0) e DateTime2 (7):
DECLARE @temp TABLE (
sdt smalldatetime,
dt datetime,
dt20 datetime2(0),
dt27 datetime2(7)
)
INSERT @temp
SELECT getdate(),getdate(),getdate(),getdate()
SELECT sdt,DATALENGTH(sdt) as sdt_bytes,
dt,DATALENGTH(dt) as dt_bytes,
dt20,DATALENGTH(dt20) as dt20_bytes,
dt27, DATALENGTH(dt27) as dt27_bytes FROM @temp
que retorna
sdt sdt_bytes dt dt_bytes dt20 dt20_bytes dt27 dt27_bytes
2015-09-11 11:26:00 4 2015-09-11 11:25:42.417 8 2015-09-11 11:25:42 6 2015-09-11 11:25:42.4170000 8
Portanto, se eu quiser armazenar informações até o segundo - mas não para o milissegundo - posso economizar 2 bytes cada um se usar o DateTime2 (0) em vez do DateTime ou DateTime2 (7).
Interpretação de strings de data em datetime
e datetime2
pode ser diferente também, ao usar fora dos EUA DATEFORMAT
definições. Por exemplo
set dateformat dmy
declare @d datetime, @d2 datetime2
select @d = '2013-06-05', @d2 = '2013-06-05'
select @d, @d2
Isso retorna 2013-05-06
(ou seja, 6 de maio) para datetime
, e 2013-06-05
(ou seja, 5 de junho) para datetime2
. No entanto, com dateformat
definido como mdy
, Ambas @d
e @d2
Retorna 2013-06-05
.
o datetime
o comportamento parece em desacordo com o Documentação do MSDN do SET DATEFORMAT
quais Estados: Alguns formatos de cordões de caracteres, por exemplo, ISO 8601, são interpretados independentemente da configuração de Dateformat. Obviamente não é verdade!
Até que fui mordido por isso, eu sempre pensei que yyyy-mm-dd
As datas seriam apenas tratadas corretamente, independentemente das configurações de idioma / localidade.
Enquanto houver aumentado precisão com DateTime2, alguns clientes não suportam encontro, Tempo, ou DateTime2 e forçá -lo a se converter em uma corda literal. Especificamente, a Microsoft menciona os problemas ODBC, OLE DB, JDBC e SQLClient com esses tipos de dados e tem um gráfico mostrando como cada um pode mapear o tipo.
Se valor compatibilidade sobre precisão, use data hora
Pergunta velha ... mas quero adicionar algo que ainda não seja declarado por ninguém aqui ... (Nota: esta é minha própria observação, então não peça nenhuma referência)
DateTime2 é mais rápido quando usado em critérios de filtro.
TLDR:
No SQL 2016, tive uma tabela com centenas de mil linhas e uma coluna DATETIME ENTRADE_TIME, porque era necessário armazenar o tempo exato até os segundos. Enquanto executa uma consulta complexa com muitas junções e uma subsenhora, quando usei onde a cláusula como:
WHERE ENTRY_TIME >= '2017-01-01 00:00:00' AND ENTRY_TIME < '2018-01-01 00:00:00'
A consulta estava bem inicialmente quando havia centenas de linhas, mas quando o número de linhas aumentou, a consulta começou a dar esse erro:
Execution Timeout Expired. The timeout period elapsed prior
to completion of the operation or the server is not responding.
Eu removi a cláusula onde, e inesperadamente, a consulta foi executada em 1 segundo, embora agora todas as linhas para todas as datas tenham sido buscadas. Eu corro a consulta interna com a cláusula onde foram necessários 85 segundos, e sem onde a cláusula levou 0,01 segundos.
Eu me deparei com muitos tópicos aqui para esta edição como Desempenho de filtragem do DateTime
Eu otimizei um pouco a consulta. Mas a velocidade real que recebi foi alterando a coluna DateTime para DateTime2.
Agora, a mesma consulta que exagerou anteriormente leva menos de um segundo.
Felicidades
De acordo com Este artigo, se você deseja ter a mesma precisão do DateTime usando o DateTime2, basta usar o DateTime2 (3). Isso deve fornecer a mesma precisão, ocupar menos bytes e fornecer um intervalo expandido.
Eu apenas tropecei em mais uma vantagem para DATETIME2
: evita um bug no python adodbapi
módulo, que explode se uma biblioteca padrão datetime
é passado o valor que possui microssegundos diferentes de zero para um DATETIME
coluna, mas funciona bem se a coluna for definida como DATETIME2
.
Select ValidUntil + 1
from Documents
O SQL acima não funcionará com um campo DateTime2. Retorna e erro "Tipo de operando Clash: DateTime2 é incompatível com int"
Adicionando 1 para obter o dia seguinte é algo que os desenvolvedores fazem com datas há anos. Agora, a Microsoft possui um campo super novo DateTime2 que não pode lidar com essa funcionalidade simples.
"Vamos usar esse novo tipo que é pior que o antigo", acho que não!
Eu penso DATETIME2
é a melhor maneira de armazenar o date
, porque tem mais eficiência do que o DATETIME
. Dentro SQL Server 2008
você pode usar DATETIME2
, ele armazena uma data e hora, leva 6-8 bytes
para armazenar e tem uma precisão de 100 nanoseconds
. Então, quem precisa de maior tempo de precisão vai querer DATETIME2
.