Podemos armazenar informações de data e hora de duas maneiras. Qual é a melhor abordagem para armazenar informações de DateTime?
Armazenando data e hora em 2 colunas separadas ou uma coluna usando DateTime ?
Você pode explicar por que essa abordagem é melhor?
(Link para documentos do MySQL para referência, a pergunta é geral, não específica para o MySQL)
Tipos de data e hora: Data e hora
Armazenar os dados em uma única coluna é a maneira preferida, pois eles estão inextricavelmente ligados. Um ponto no tempo é uma única informação, não duas.
Uma maneira comum de armazenar dados de data/hora, empregada "nos bastidores" por muitos produtos, é convertê-los em um valor decimal em que "data" é a parte inteira do valor decimal e "hora" é a fração valor. Assim, 1900-01-01 00:00:00 é armazenado como 0.0 e 20 de setembro de 2016 9:34:00 é armazenado como 42631.39861. 42631 é o número de dias desde 1900-01-01. .39861 é a parte do tempo decorrido desde a meia-noite. Não use um tipo decimal diretamente para fazer isso, use um tipo de data/hora explícito; meu ponto aqui é apenas uma ilustração.
Armazenar os dados em duas colunas separadas significa que você precisará combinar os valores de ambas as colunas sempre que quiser ver se um determinado momento é anterior ou posterior ao valor armazenado.
Se você armazenar os valores separadamente, invariavelmente encontrará "bugs" difíceis de detectar. Tomemos por exemplo o seguinte:
No código acima, estamos criando uma tabela de teste, preenchendo-a com dois valores e realizando uma consulta simples nesses dados. O primeiro
SELECT
retorna as duas linhas, porém o segundoSELECT
retorna apenas uma única linha, o que pode não ser o resultado desejado:A maneira correta de filtrar um intervalo de data/hora em que os valores estão em colunas discretas, conforme apontado por @ypercube nos comentários, é:
Se você precisar separar o componente de tempo para fins de análise , considere adicionar uma coluna calculada e persistente para a parte de tempo do valor:
A coluna persistente pode ser indexada permitindo classificações rápidas, etc., por hora do dia.
Se você está pensando em dividir a data e hora em dois campos para fins de exibição, você deve perceber que a formatação deve ser feita no cliente, não no servidor.
Vou fornecer uma opinião divergente para as outras respostas.
Se os componentes de data e hora forem necessários juntos, ou seja, uma entrada é inválida se contiver um, mas não o outro (ou for NULL em um, mas não no outro), armazená-lo em uma única coluna faz sentido pelas razões fornecidas em outros respostas.
No entanto, pode acontecer que um ou ambos os componentes sejam individualmente opcionais. Nesse caso, seria incorreto armazená-lo em uma única coluna. Fazer isso forçaria você a representar valores NULL de forma arbitrária, por exemplo, armazenando a hora como 00:00:00.
Aqui estão alguns exemplos:
Você está registrando as viagens do veículo para deduções do imposto de milhagem. Saber a hora exata da viagem seria útil, mas se um funcionário não anotou e esqueceu, a data ainda deve ser registrada por si mesma (data obrigatória, hora opcional).
Você está realizando uma pesquisa para descobrir a que horas as pessoas almoçam e pede aos participantes que preencham um formulário com uma amostra de seus horários de almoço, incluindo datas. Alguns não se preocupam em preencher a data e você não deseja descartar os dados, pois são os horários que realmente importam (data opcional, hora obrigatória).
Veja esta pergunta relacionada para abordagens alternativas.
Prefiro sempre armazenar isso como uma única coluna, a menos que haja alguma demanda específica de negócios/aplicativos. Abaixo estão meus pontos -
No SQL Server é melhor armazenar DataTime como um campo. Se você criar um índice na coluna DataTime, ele poderá ser usado como pesquisa de data e como pesquisa de data e hora. Portanto, se você precisar limitar todos os registros que existem para a data específica, ainda poderá usar o índice sem precisar fazer nada de especial. Se você precisar consultar a parte do tempo, não poderá usar o mesmo índice e, portanto, se tiver um caso de negócios em que se preocupa mais com a hora do dia do que com DateTime, armazene-o separadamente, pois precisará criar um índice sobre ele e melhorar o desempenho.
De fato, é uma pena que não exista um tipo padrão de cross-DBMS para isso (como INT e VARCHAR são para inteiros e valores de string). As duas abordagens de banco de dados cruzadas que encontrei até agora estão usando colunas VARCHAR/CHAR para armazenar valores DataTime como strings formatadas de acordo com o padrão ISO 8601 (mais conveniente, legível por humanos) e usando BIGINT para armazená-los como carimbos de data e hora POSIX (armazenados mais eficiente, mais rápido, mais fácil de manipular matematicamente).
Depois de ler um monte de coisas, o horário UTC Unix no BIGINT parece ser a solução ideal. TZDB timesone ID em VARCHAR para armazenamento de fuso horário, se necessário. Alguns argumentos:
TIMESTAMP e DATETIME fazem um monte de conversões enigmáticas em segundo plano que parecem ser complexas e não claras. O servidor alterna da hora local para UTC ou para a hora do servidor e vice-versa, às vezes ou não. Um monte de sobrecarga escondida para cada função.
BIGINT (8kb) é pelo menos tão leve ou mais leve que DECIMAL necessário para armazenamento no formato xxxxxx.xxxxxx, que é praticamente armazenado como dois INTs + algo pelo MySQL . E é o suficiente para armazenar séculos à frente.
Praticamente todas as principais linguagens de programação têm bibliotecas de funções padrão para trabalhar com o tempo Unix.
As operações matemáticas com BIGINT devem ser tão rápidas ou mais rápidas do que qualquer outra coisa em qualquer hardware.
Claro que todos os itens acima são relevantes para grandes projetos internacionais. Para algo pequeno, ir com o formato padrão do framework escolhido parece ser bom o suficiente.