Ich wurde gebeten, etwas zu erstellen, das die täglichen Kosten für das Sammeln auf Konten protokolliert, und ich versuche, ein Datenbanktabellenschema zu finden, das dies unterstützt.
Folgendes weiß ich
- Das Unternehmen hat über 2,5 Millionen Konten
- Davon arbeiten sie derzeit durchschnittlich 200.000 pro Monat (dies ändert sich mit dem Personalbestand, der derzeit niedrig ist).
- Sie haben 13 verschiedene Kostentypen, die sie verfolgen möchten, und sie haben gewarnt, dass sie in Zukunft weitere hinzufügen könnten
- Sie möchten, dass die Kosten täglich nachverfolgt werden
- Die Kosten werden nicht auf das gesamte Inventar aufgeteilt. Sie sind entweder auf die Anzahl der Konten aufgeteilt, die pro Monat bearbeitet werden (200.000), oder Benutzer können Konto-IDs eingeben, um Kosten auf eine Gruppe von Konten anzuwenden, oder sie können einfach angeben, auf welche Konten die Kosten angewendet werden sollen.
Mein erster Gedanke war eine normalisierte Datenbank:
AccountId Datum CostTypeId Menge
Mein Problem dabei ist, machen Sie die Mathematik. Dieser Tisch wird schnell riesig. Angenommen, alle 13 Kostentypen werden für den aktuellen Monat auf alle bearbeiteten Konten angewendet 200k * 13 * N days in month
, entspricht dies etwa 75 bis 80 Millionen Datensätzen pro Monat oder nahezu einer Milliarde Datensätzen pro Jahr.
Mein zweiter Gedanke war, es ein bisschen zu denormalisieren
AccountId Datum Gesamtkosten CostType1 CostType2 CostType3 CostType4 CostType5 CostType6 CostType7 CostType8 CostType9 CostType10 CostType11 CostType12 CostType13
Diese Methode ist denormalisierter und kann bis zu 6 Millionen Datensätze pro Monat ( 200k * N days in month
) oder etwa 72 Millionen pro Jahr erstellen. Dies ist viel weniger als die erste Methode. Wenn sich das Unternehmen jedoch in Zukunft für einen neuen Kostentyp entscheidet, muss eine weitere Datenbankspalte hinzugefügt werden.
Welche der beiden Methoden bevorzugen Sie? Warum? Gibt es eine andere Alternative, die dies besser bewältigen könnte?
Am meisten interessiert mich die Berichterstattung über die Leistung, sowohl über zusammengefasste als auch über detaillierte Berichte. Der Job, der die Kosten auf die Konten verteilt, wird jede Nacht ausgeführt, wenn niemand in der Nähe ist. Ein sekundäres Anliegen ist die Datenbankgröße. Die vorhandene Datenbank ist bereits fast 300 GB groß, und ich glaube, der Speicherplatz auf der Festplatte beträgt etwa 500 GB.
Die Datenbank ist SQL Server 2005
Antworten:
Eine Milliarde Platten pro Jahr sind nicht viel.
Mit Partitionierung (pro Kostenart vielleicht) und Archivierung ist es verwaltbar.
Die Anzahl der zu speichernden Datenelemente beträgt immer noch 200.000 * 13 * N. Als Spalten erhalten Sie weniger Zeilen pro Seite und es wird mehr Platz benötigt als als Zeilen. Sie können gewinnen, wenn "CostType1" kein Datentyp mit fester Länge ist, aber es ist marginal.
"KISS" wie sie sagen
quelle
In diesem Fall würde ich mich mehr auf Indizes konzentrieren, einschließlich der Abdeckung von Indizes nach Bedarf. Ich würde mir auch einige der Tools ansehen, die SQL Server für den Umgang mit sehr großen Tabellen bereitstellt, z. B. die Tabellenpartitionierung.
Stellen Sie sich das so vor, obwohl die Tabelle 80 Milliarden Datensätze enthält, werden die Datensätze, an denen Sie tatsächlich interessiert sind, bei richtiger Indizierung physisch auf der Festplatte zusammengefasst. Aufgrund der Art und Weise, wie Daten in SQL Server organisiert sind, können sich nach Indexgrenzen aufgeteilte Daten auch in einer anderen Tabelle befinden, da nicht die gesamte Tabelle gelesen werden muss, um die erforderlichen Informationen zu erhalten.
Wenn Sie die Tabelle auch partitionieren, können Sie die Zugriffszeit und die Einfügezeit verbessern.
quelle
Ich würde mich normalisieren. Wir haben die Kostenrechnung für die Rentabilität von Kundenkonten bei einer Bank durchgeführt und mit Hunderten von Treibern, die monatlich über Millionen von Konten nach Kostenstelle oder Hauptbuch oder nach verschiedenen anderen Techniken zugeordnet wurden, über 250 Millionen Zeilen von Einzelkosten generiert.
Zum Beispiel wurden die Gesamtkosten für die Wartung von Geldautomaten auf Konten aufgeteilt, die Geldautomaten verwendet hatten, basierend auf der relativen Nutzungsmenge. Wenn also 1 Million US-Dollar für die Wartung von Geldautomaten ausgegeben wurden und nur 5 Kunden diese jeweils einmal und ein Kunde sie fünfmal verwendeten, kostete dieser eine Kunde die Bank 0,5 Millionen US-Dollar und der andere die Bank jeweils 0,1 Millionen US-Dollar. Andere Treiber könnten sehr viel komplexer sein.
Letztendlich werden Sie wahrscheinlich feststellen, dass es spärlich ist - bestimmte Konten bekommen keine Kosten von bestimmten Quellen / Treibern - und einige Konten bekommen nichts. In einem normalisierten Modell existieren diese Zeilen nicht. Im denormalisierten Modell ist die Zeile mit einigen leeren Spalten vorhanden. Außerdem sollte sich in einem spärlich normalisierten Modell die Leistung verbessern, da das Vorhandensein einer Zeile in der Regel schneller überprüft werden kann (mit deckendem Index für CostType) als das Überprüfen aller Zeilen mit Nicht-NULL in einem bestimmten "Bucket" (auch mit Indizes für jede Betragsspalte - die Sie sehen können, beginnen sehr verschwenderisch zu werden).
quelle
Ungeachtet des Leistungsvorteils würde ich mich definitiv für Option 1 entscheiden. Option 2 würde meiner Meinung nach Peter berauben, um Paul zu bezahlen.
quelle
Ich entschied mich für Option 1, und wenn die Berichtsgeschwindigkeit später zu einem Problem wurde, fügte ich Tabelle 2 hinzu und füllte sie in einer Art automatisiertem Übernacht- / Off-Peak-Prozess in eine Berichtsdatenbank ein.
Sie können dann auch erwägen, die tägliche Tabelle-2-Struktur in weitere wöchentliche, monatliche, vierteljährliche und jährliche Rollups umzuwandeln, falls dies gerechtfertigt ist.
Aber wie gesagt, ich würde mich auch dafür entscheiden, die "Rohdaten" in der richtigen (normalisierten) Form zu speichern.
quelle
In Anbetracht der von Ihnen erwähnten Mengen würde ich die zweite Option wählen, jedoch ohne TotalCost. Man könnte sagen, das ist noch normalisiert.
Bearbeiten: Alternativ und abhängig von Ihren Anforderungen und der Größe der Konto-ID können Sie auch Folgendes berücksichtigen:
Mit diesem Entwurf können Sie der ersten Tabelle immer noch eine denormalisierte TotalCost hinzufügen und diese nachts neu berechnen lassen, sodass einige Berichte nur für die erste Tabelle ausgeführt werden können.
quelle
TotalCost
da drin, weil der Großteil der Berichterstattung zusammengefasst ist, und ich dachte, es wäre schneller, einen einzelnen Wert abzufragen, als 13 verschiedene Werte hinzuzufügen.Sie sollten die firs-Tabelle tatsächlich in zwei Tabellen unterteilen, damit Sie eine Unterabfrage verwenden und die zweite Zeile als Spalte oder viele Spalten auswählen können. Auf diese Weise ist es flexibler und auf diese Weise können Sie ein Ergebnis wie das zweite leichter erhalten.
quelle