Estou construindo um banco de dados com o Postgres, onde haverá um monte de coisas agrupadas por month
e year
, mas nunca pelo date
.
- Eu poderia criar números inteiros
month
eyear
colunas e usá-los. - Ou eu poderia ter uma
month_year
coluna e sempre definir oday
1.
O primeiro parece um pouco mais simples e mais claro se alguém estiver olhando para os dados, mas o segundo é bom porque usa um tipo adequado.
postgresql
database-design
datetime
David N. Welton
fonte
fonte
month
que contém dois números inteiros. Mas eu acho que se você nunca, nunca precisar o dia do mês, usando dois inteiros é provavelmente mais fácilRespostas:
Pessoalmente, se é uma data, ou pode ser uma data, sugiro sempre armazená-lo como um. É mais fácil trabalhar com isso como regra geral.
Você pode ter uma data que suportará o dia, se você precisar, ou uma
smallint
para o ano e o mês, que nunca suportará a precisão extra.Dados de amostra
Vamos ver um exemplo agora. Vamos criar 1 milhão de datas para nossa amostra. São aproximadamente 5.000 linhas por 200 anos entre 1901 e 2100. Todo ano deve ter algo para todo mês.
Teste
Simples
WHERE
Agora podemos testar essas teorias de não usar data. Corri cada uma delas algumas vezes para aquecer as coisas.
Agora, vamos tentar o outro método com eles separados
Para ser justo, nem todos são 0,749. Alguns são um pouco mais ou menos, mas isso não importa. Eles são todos relativamente iguais. Simplesmente não é necessário.
Dentro de um mês
Agora, vamos nos divertir com isso. Digamos que você queira encontrar todos os intervalos dentro de 1 mês a partir de janeiro de 2014 (o mesmo mês que usamos acima).
Compare isso com o método combinado
É mais lento e mais feio.
GROUP BY
/ORDER BY
Método combinado,
E novamente com o método composto
Conclusão
Geralmente, deixe as pessoas inteligentes fazerem o trabalho duro. Datemath é difícil, meus clientes não me pagam o suficiente. Eu costumava fazer esses testes. Eu estava duro para concluir que poderia obter melhores resultados do que
date
. Eu parei de tentar.ATUALIZAÇÕES
@a_horse_with_no_name sugerido para o meu teste dentro de um mês
WHERE (year, month) between (2013, 12) and (2014,2)
. Na minha opinião, apesar de legal, é uma consulta mais complexa e prefiro evitá-la, a menos que haja um ganho. Infelizmente, ainda era mais lento, apesar de estar próximo - o que é mais difícil de tirar deste teste. Simplesmente não importa muito.fonte
date
é o caminho a percorrer na maioria dos casos.Como alternativa ao método proposto por Evan Carroll, que considero provavelmente a melhor opção, usei em algumas ocasiões (e não especialmente ao usar o PostgreSQL) apenas uma
year_month
coluna do tipoINTEGER
(4 bytes), calculada comoOu seja, você codifica o mês nos dois dígitos decimais mais à direita (dígito 0 e dígito 1) do número inteiro e o ano nos dígitos 2 a 5 (ou mais, se necessário).
Esta é, até certo ponto, a alternativa de um homem pobre para criar seu próprio
year_month
tipo e operadores. Ele tem algumas vantagens, principalmente "clareza de intenção", e algumas economias de espaço (não no PostgreSQL, eu acho), e também alguns inconvenientes, por ter duas colunas separadas.Você pode garantir que os valores sejam válidos apenas adicionando um
Você pode ter uma
WHERE
cláusula parecida com:e funciona de forma eficiente (se a
year_month
coluna estiver adequadamente indexada, é claro).Você pode agrupar
year_month
da mesma maneira que faria com uma data e com a mesma eficiência (pelo menos).Se você precisar separar
year
emonth
, o cálculo é direto:O que é inconveniente : se você deseja adicionar 15 meses a um,
year_month
precisa calcular (se não cometi um erro ou supervisão):Se você não tomar cuidado, isso pode ser propenso a erros.
Se você deseja obter o número de meses entre dois meses, precisa fazer alguns cálculos semelhantes. É isso (com muitas simplificações) o que realmente acontece nos bastidores da aritmética das datas, que felizmente está escondido de nós por meio de funções e operadores já definidos.
Se você precisar de muitas dessas operações, o uso
year_month
não é muito prático. Caso contrário, é uma maneira muito clara de deixar clara sua intenção.Como alternativa, você pode definir um
year_month
tipo e definir um operadoryear_month
+interval
e também outroyear_month
-year_month
... e ocultar os cálculos. Na verdade, nunca fiz um uso tão pesado que senti a necessidade na prática. Adate
-date
na verdade está escondendo algo parecido.fonte
Como alternativa ao método de joanolo =) (desculpe, eu estava ocupado, mas queria escrever isso)
ALEGRIA BIT
Nós vamos fazer a mesma coisa, mas com bits. Um
int4
no PostgreSQL é um número inteiro assinado, variando de -2147483648 a +2147483647Aqui está uma visão geral da nossa estrutura.
Armazenando mês.
pow(2,4)
e 4 bits .Aqui está o nosso mapa de bits de onde os meses são armazenados.
Meses, 1 de janeiro a 12 de dezembro
Anos. Os 28 bits restantes nos permitem armazenar nossas informações do ano
Neste ponto, precisamos decidir como queremos fazer isso. Para nossos propósitos, poderíamos usar um deslocamento estático; se precisarmos cobrir apenas 5.000 dC, poderíamos voltar para o
268,430,455 BC
que abrange praticamente todo o Mesozóico e tudo o que é útil para avançar.E agora temos os rudimentos do nosso tipo, que devem expirar em 2.700 anos.
Então, vamos trabalhar para fazer algumas funções.
Um teste rápido mostra esse funcionamento ..
Agora temos funções que podemos usar em nossos tipos binários.
Poderíamos ter cortado mais um pouco da parte assinada, armazenado o ano como positivo e, depois, classificado naturalmente como um int assinado. Se a velocidade fosse uma prioridade mais alta que o espaço de armazenamento, essa seria a rota que seguimos. Mas, por enquanto, temos uma data que funciona com o mesozóico.
Posso atualizar mais tarde com isso, apenas por diversão.
fonte