Ich baue mit Postgres eine Datenbank auf, in der viele Dinge nach month
und gruppiert werden year
, aber niemals nach date
.
- Ich könnte Integer
month
undyear
Spalten erstellen und diese verwenden. - Oder ich könnte eine
month_year
Spalte haben und die immerday
auf 1 setzen.
Ersteres scheint ein bisschen einfacher und klarer zu sein, wenn jemand die Daten betrachtet. Letzteres ist jedoch insofern von Vorteil, als es einen geeigneten Typ verwendet.
postgresql
database-design
datetime
David N. Welton
quelle
quelle
month
, der zwei Ganzzahlen enthält. Aber ich denke, wenn Sie niemals den Tag des Monats brauchen, ist es wahrscheinlich einfacher, zwei ganze Zahlen zu verwendenAntworten:
Persönlich, wenn es ein Datum ist oder ein Datum sein kann, empfehle ich, es immer als eines zu speichern. Als Faustregel ist es einfach einfacher, damit zu arbeiten.
Sie können ein Datum haben, das den Tag unterstützt, wenn Sie es jemals benötigen, oder ein Datum
smallint
für Jahr und Monat, das niemals die zusätzliche Genauigkeit unterstützt.Beispieldaten
Sehen wir uns jetzt ein Beispiel an. Erstellen wir eine Million Daten für unser Beispiel. Dies sind ungefähr 5.000 Zeilen für 200 Jahre zwischen 1901 und 2100. Jedes Jahr sollte für jeden Monat etwas dabei sein.
Testen
Einfach
WHERE
Jetzt können wir diese Theorien der Nichtverwendung von Datumsangaben testen. Ich habe sie jeweils einige Male ausgeführt, um die Dinge aufzuwärmen.
Versuchen wir nun die andere Methode mit ihnen getrennt
Fairerweise sind sie nicht alle 0.749. Einige sind ein bisschen mehr oder weniger, aber es spielt keine Rolle. Sie sind alle relativ gleich. Es wird einfach nicht benötigt.
Innerhalb eines Monats
Jetzt lass uns Spaß damit haben. Angenommen, du möchtest alle Intervalle innerhalb eines Monats ab Januar 2014 finden (der gleiche Monat, den wir oben verwendet haben).
Vergleichen Sie das mit der kombinierten Methode
Es ist sowohl langsamer als auch hässlicher.
GROUP BY
/ORDER BY
Kombinierte Methode,
Und wieder mit der Composite-Methode
Fazit
Lassen Sie im Allgemeinen die klugen Leute die harte Arbeit erledigen. Datemath ist schwer, meine Kunden zahlen mir nicht genug. Ich habe diese Tests gemacht. Es fiel mir schwer, jemals zu dem Schluss zu kommen, dass ich bessere Ergebnisse erzielen könnte als
date
. Ich habe aufgehört, es zu versuchen.AKTUALISIERUNG
@a_horse_with_no_name empfohlen für meinen Test innerhalb eines Monats
WHERE (year, month) between (2013, 12) and (2014,2)
. Meiner Meinung nach ist das zwar cool, aber eine komplexere Abfrage, und ich würde sie lieber vermeiden, wenn es keinen Gewinn gäbe. Leider war es immer noch langsamer, obwohl es in der Nähe ist - das ist eher der Nachteil dieses Tests. Es macht einfach nicht viel aus.quelle
date
Ist in den meisten Fällen der richtige Weg.Als Alternative zu der von Evan Carroll vorgeschlagenen Methode, die ich für die wahrscheinlich beste Option halte, habe ich in einigen Fällen (und nicht speziell bei Verwendung von PostgreSQL) nur eine
year_month
Spalte vom TypINTEGER
(4 Byte) verwendet, die als berechnet wurdeDas heißt, Sie codieren den Monat mit den beiden am weitesten rechts stehenden Dezimalstellen (Ziffer 0 und Ziffer 1) der Ganzzahl und das Jahr mit den Ziffern 2 bis 5 (oder, falls erforderlich, mehr).
Dies ist in gewissem Maße die Alternative eines armen Mannes zum Aufbau eines eigenen
year_month
Typs und eigener Betreiber. Es hat einige Vorteile, vor allem "Klarheit der Absicht", und einige Platzersparnisse (nicht in PostgreSQL, denke ich) und auch einige Unannehmlichkeiten, über zwei separate Spalten.Sie können die Gültigkeit der Werte garantieren, indem Sie einfach a hinzufügen
Sie können eine
WHERE
Klausel haben , die wie folgt aussieht:und es funktioniert effizient (wenn die
year_month
Spalte natürlich richtig indiziert ist).Sie können auf
year_month
die gleiche Weise wie mit einem Datum und (mindestens) mit der gleichen Effizienz gruppieren .Wenn Sie trennen
year
undmonth
ist die Berechnung einfach:Was ist unpraktisch : Wenn Sie einen Zeitraum von 15 Monaten verlängern möchten,
year_month
müssen Sie Folgendes berechnen (wenn ich keinen Fehler oder Fehler gemacht habe):Wenn Sie nicht aufpassen, kann dies fehleranfällig sein.
Wenn Sie die Anzahl der Monate zwischen zwei year_months ermitteln möchten, müssen Sie einige ähnliche Berechnungen durchführen. Das ist (mit vielen Vereinfachungen), was wirklich unter der Haube mit Datumsarithmetik passiert, was uns zum Glück durch bereits definierte Funktionen und Operatoren verborgen bleibt.
Wenn Sie viele dieser Operationen benötigen, ist die Verwendung
year_month
nicht allzu praktisch. Wenn Sie dies nicht tun, ist dies eine sehr klare Methode, um Ihre Absichten deutlich zu machen.Alternativ können Sie einen
year_month
Typ definieren und einen Operatoryear_month
+interval
sowie ein anderesyear_month
-year_month
... definieren und die Berechnungen ausblenden. Ich habe eigentlich noch nie so viel gebraucht, um das Bedürfnis in der Praxis zu spüren. Adate
-date
versteckt Sie tatsächlich etwas Ähnliches.quelle
Als Alternative zu Joanolos Methode =) (Entschuldigung, ich war beschäftigt, wollte dies aber schreiben)
BIT JOY
Wir werden das Gleiche tun, aber mit Bits. Eine
int4
in PostgreSQL ist eine Ganzzahl mit Vorzeichen, die von -2147483648 bis +2147483647 reichtHier finden Sie eine Übersicht über unsere Struktur.
Speichermonat.
pow(2,4)
sind 4 Bits .Hier ist unsere Bitmap, wo Monate gespeichert sind.
Monate, 1. Januar - 12. Dezember
Jahre. Die verbleibenden 28 Bits ermöglichen es uns, unsere Jahresinformationen zu speichern
An diesem Punkt müssen wir entscheiden, wie wir das tun wollen. Für unsere Zwecke könnten wir einen statischen Offset verwenden, wenn wir nur 5.000 n. Chr. Abdecken müssten, könnten wir zurückgehen,
268,430,455 BC
was so ziemlich das gesamte Mesozoikum und alles Nützliche in der Zukunft abdeckt .Und jetzt haben wir die Grundlagen unserer Art, die in 2.700 Jahren verfallen werden.
Machen wir uns also an die Arbeit, um einige Funktionen zu erstellen.
Ein schneller Test zeigt, dass dies funktioniert.
Jetzt haben wir Funktionen, die wir für unsere Binärtypen verwenden können.
Wir hätten noch ein Bit von dem signierten Teil abschneiden können, das Jahr als positiv speichern und es dann natürlich als signiertes int sortieren lassen. Wenn Geschwindigkeit eine höhere Priorität als Speicherplatz gehabt hätte, wäre dies die Route gewesen, die wir eingeschlagen haben. Aber vorerst haben wir ein Datum, das mit dem Mesozoikum zusammenarbeitet.
Ich kann später damit aktualisieren, nur zum Spaß.
quelle