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?

Foi útil?

Solução

A documentação do MSDN para data hora recomenda usar DateTime2. Aqui está a recomendação deles:

Use o time, date, datetime2 e datetimeoffset Tipos de dados para novo trabalho. Esses tipos estão alinhados com o padrão SQL. Eles são mais portáteis. time, datetime2 e datetimeoffsetForneç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)

  1. maior faixa de valores
  2. Melhor Precisão
  3. menor espaço de armazenamento (Se a precisão opcional especificada pelo usuário for especificada)

SQL Date and time data types compare - datetime,datetime2,date,TIME

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:

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.

  1. 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).

  1. 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 DateTimeintervalo 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 Dayde 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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top