Je construis une base de données avec Postgres où il y aura beaucoup de regroupements de choses par month
et year
, mais jamais par date
.
- Je pourrais créer des entiers
month
et desyear
colonnes et les utiliser. - Ou je pourrais avoir une
month_year
colonne et toujours mettre leday
à 1.
Le premier semble un peu plus simple et plus clair si quelqu'un regarde les données, mais le second est agréable en ce qu'il utilise un type approprié.
postgresql
database-design
datetime
David N. Welton
la source
la source
month
qui contient deux entiers. Mais je pense que si vous n'avez jamais, jamais besoin du jour du mois, utiliser deux entiers est probablement plus facileRéponses:
Personnellement, si c'est une date, ou peut être une date, je suggère de toujours la stocker comme une seule. C'est juste plus facile de travailler avec en règle générale.
Vous pouvez avoir une date qui prendra en charge le jour si vous en avez besoin, ou une
smallint
pour l'année et le mois qui ne prendra jamais en charge la précision supplémentaire.Exemples de données
Regardons maintenant un exemple. Créons 1 million de dates pour notre échantillon. Cela représente environ 5 000 lignes pendant 200 ans entre 1901 et 2100. Chaque année devrait avoir quelque chose pour chaque mois.
Essai
Facile
WHERE
Maintenant, nous pouvons tester ces théories de ne pas utiliser de date .. J'ai exécuté chacune de ces quelques fois afin de réchauffer les choses.
Maintenant, essayons l'autre méthode avec eux séparément
En toute honnêteté, ils ne sont pas tous 0,749 ... certains sont un peu plus ou moins, mais cela n'a pas d'importance. Ils sont tous relativement les mêmes. Ce n'est tout simplement pas nécessaire.
Dans un mois
Maintenant, amusons-nous avec cela. Disons que vous voulez trouver tous les intervalles dans un délai d'un mois à partir de janvier 2014 (le même mois que nous avons utilisé ci-dessus).
Comparez cela à la méthode combinée
C'est à la fois plus lent et plus laid.
GROUP BY
/ORDER BY
Méthode combinée,
Et encore une fois avec la méthode composite
Conclusion
En règle générale, laissez les gens intelligents faire le travail difficile. Datemath est difficile, mes clients ne me paient pas assez. J'avais l'habitude de faire ces tests. J'avais du mal à conclure que je pouvais obtenir de meilleurs résultats que
date
. J'ai arrêté d'essayer.MISES À JOUR
@a_horse_with_no_name suggéré pour mon dans un délai d'un mois test
WHERE (year, month) between (2013, 12) and (2014,2)
. À mon avis, bien que cool, c'est une requête plus complexe et je préfère l'éviter sauf s'il y a un gain. Hélas, il était encore plus lent bien qu'il soit proche - ce qui est plus à retenir de ce test. Cela n'a pas beaucoup d'importance.la source
date
c'est la voie à suivre dans la plupart des cas.Comme alternative à la méthode proposée par Evan Carroll, que je considère probablement la meilleure option, j'ai utilisé à certaines occasions (et pas spécialement lors de l'utilisation de PostgreSQL) juste une
year_month
colonne, de typeINTEGER
(4 octets), calculée commeAutrement dit, vous codez le mois sur les deux chiffres décimaux les plus à droite (chiffre 0 et chiffre 1) du nombre entier et l'année sur les chiffres 2 à 5 (ou plus, si nécessaire).
C'est, dans une certaine mesure, l' alternative d' un pauvre homme à la construction de votre propre
year_month
type et opérateurs. Il a certains avantages, principalement la «clarté de l'intention», et quelques économies d'espace (pas dans PostgreSQL, je pense), ainsi que quelques inconvénients, par rapport à deux colonnes distinctes.Vous pouvez garantir que les valeurs sont valides en ajoutant simplement un
Vous pouvez avoir une
WHERE
clause ressemblant à ceci:et cela fonctionne efficacement (si la
year_month
colonne est correctement indexée, bien sûr).Vous pouvez regrouper par
year_month
la même manière que vous pourriez le faire avec une date et avec la même efficacité (au moins).Si vous devez séparer
year
etmonth
, le calcul est simple:Ce qui est gênant : si vous voulez ajouter 15 mois à un,
year_month
vous devez calculer (si je n'ai pas fait d'erreur ou de surveillance):Si vous ne faites pas attention, cela peut être sujet à des erreurs.
Si vous souhaitez obtenir le nombre de mois entre deux year_months, vous devez effectuer des calculs similaires. C'est (avec beaucoup de simplifications) ce qui se passe vraiment sous le capot avec l'arithmétique des dates, qui nous est heureusement caché par des fonctions et des opérateurs déjà définis.
Si vous avez besoin de beaucoup de ces opérations, l'utilisation
year_month
n'est pas trop pratique. Si vous ne le faites pas, c'est une façon très claire de clarifier votre intention.Alternativement, vous pouvez définir un
year_month
type, définir un opérateuryear_month
+interval
, ainsi qu'un autreyear_month
-year_month
... et masquer les calculs. En fait, je n'ai jamais fait une telle utilisation au point d'en ressentir le besoin dans la pratique. Adate
-date
vous cache en fait quelque chose de similaire.la source
Comme alternative à la méthode de joanolo =) (désolé j'étais occupé mais je voulais écrire ceci)
BIT JOY
Nous allons faire la même chose, mais avec des bits. Un
int4
dans PostgreSQL est un entier signé, allant de -2147483648 à +2147483647Voici un aperçu de notre structure.
Mois de stockage.
pow(2,4)
soit 4 bits .Voici notre bitmap de l'endroit où les mois sont stockés.
Mois, 1er janvier - 12 décembre
Ans. Les 28 bits restants nous permettent de stocker nos informations sur l'année
À ce stade, nous devons décider comment nous voulons procéder. Pour nos besoins, nous pourrions utiliser un décalage statique, si nous avons seulement besoin de couvrir 5 000 AD, nous pourrions revenir à
268,430,455 BC
ce qui couvre à peu près l'intégralité du Mésozoïque et tout ce qui est utile pour aller de l'avant.Et, maintenant, nous avons les rudiments de notre type, qui expireront dans 2 700 ans.
Commençons donc à créer certaines fonctions.
Un test rapide montre que cela fonctionne ..
Nous avons maintenant des fonctions que nous pouvons utiliser sur nos types binaires.
Nous aurions pu couper un bit de plus de la partie signée, enregistrer l'année comme positive, puis la faire trier naturellement comme un entier signé. Si la vitesse était une priorité plus élevée que l'espace de stockage, cela aurait été la voie que nous empruntons. Mais pour l'instant, nous avons une date qui fonctionne avec le Mésozoïque.
Je peux mettre à jour plus tard avec ça, juste pour le plaisir.
la source