MongoDB Schema Design - Viele kleine Dokumente oder weniger große Dokumente?

86

Hintergrund
Ich bin Prototyp einer Konvertierung von unserer RDBMS-Datenbank in MongoDB. Während der Denormalisierung habe ich anscheinend zwei Möglichkeiten: eine, die zu vielen (Millionen) kleineren Dokumenten führt, oder eine, die zu weniger (Hunderttausenden) großen Dokumenten führt.

Wenn ich es auf ein einfaches Analog reduzieren könnte, wäre es der Unterschied zwischen einer Sammlung mit weniger Kundendokumenten wie diesem (in Java):

Klasse Kunde {
    privater Stringname;
    private Adresse Adresse;
    // Jede CreditCard verfügt über Hunderte von Zahlungsinstanzen
    private Set <CreditCard> creditCards;
}}

oder eine Sammlung mit vielen, vielen Zahlungsdokumenten wie diesen:

Klasse Zahlung {
    Privatkunde Kunde;
    private CreditCard creditCard;
    privates Datum payDate;
    private float payAmount;
}}

Frage
Ist MongoDB so konzipiert, dass es viele, viele kleine Dokumente oder weniger große Dokumente bevorzugt? Hängt die Antwort hauptsächlich davon ab, welche Abfragen ich ausführen möchte? (dh wie viele Kreditkarten hat Kunde X? vs Wie hoch war der durchschnittliche Betrag, den alle Kunden im letzten Monat bezahlt haben?)

Ich habe mich viel umgesehen, bin aber nicht auf Best Practices für MongoDB-Schemata gestoßen, die mir bei der Beantwortung meiner Frage helfen würden.

Andre
quelle

Antworten:

81

Sie müssen auf jeden Fall für die von Ihnen ausgeführten Abfragen optimieren.

Hier ist meine beste Vermutung basierend auf Ihrer Beschreibung.

Sie möchten wahrscheinlich alle Kreditkarten für jeden Kunden kennen, also behalten Sie eine Reihe von Kreditkarten im Kundenobjekt. Wahrscheinlich möchten Sie auch eine Kundenreferenz für jede Zahlung haben. Dadurch wird der Zahlungsbeleg relativ klein gehalten.

Das Zahlungsobjekt hat automatisch eine eigene ID und einen eigenen Index. Möglicherweise möchten Sie auch einen Index zur Kundenreferenz hinzufügen.

Auf diese Weise können Sie schnell nach Zahlungen des Kunden suchen, ohne jedes Mal das gesamte Kundenobjekt speichern zu müssen.

Wenn Sie Fragen wie "Was war der durchschnittliche Betrag, den alle Kunden im letzten Monat gezahlt haben" beantworten möchten, möchten Sie stattdessen eine Karte / Reduzierung für einen größeren Datensatz. Sie erhalten diese Antwort nicht "in Echtzeit". Sie werden feststellen, dass das Speichern eines "Verweises" auf den Kunden wahrscheinlich gut genug für diese Kartenreduzierungen ist.

Um Ihre Frage direkt zu beantworten: Ist MongoDB so konzipiert, dass es viele, viele kleine Dokumente oder weniger große Dokumente bevorzugt?

MongoDB wurde entwickelt, um indizierte Einträge sehr schnell zu finden. MongoDB ist sehr gut darin, ein paar Nadeln in einem großen Heuhaufen zu finden. MongoDB ist nicht sehr gut darin, die meisten Nadeln im Heuhaufen zu finden. Bauen Sie Ihre Daten also auf Ihre häufigsten Anwendungsfälle auf und schreiben Sie Map / Reduce-Jobs für die selteneren Anwendungsfälle.

Gates VP
quelle
30

Laut der eigenen Dokumentation von MongoDB scheint es für viele kleine Dokumente konzipiert zu sein.

Aus Best Practices für die Leistung von MongoDB :

Die maximale Größe für Dokumente in MongoDB beträgt 16 MB. In der Praxis sind die meisten Dokumente einige Kilobyte oder weniger. Betrachten Sie Dokumente eher als Zeilen in einer Tabelle als als die Tabellen selbst. Anstatt Listen von Datensätzen in einem einzelnen Dokument zu verwalten, machen Sie stattdessen jeden Datensatz zu einem Dokument.

Aus 6 Faustregeln für das MongoDB-Schemadesign: Teil 1 :

Eins-zu-wenige-Modellierung

Ein Beispiel für "Eins-zu-Wenig" könnten die Adressen für eine Person sein. Dies ist ein guter Anwendungsfall für das Einbetten. Sie würden die Adressen in ein Array innerhalb Ihres Person-Objekts einfügen.

Eins zu viele

Ein Beispiel für „Eins-zu-Viele“ könnten Teile für ein Produkt in einem Ersatzteilbestellsystem sein. Jedes Produkt kann bis zu mehreren hundert Ersatzteile enthalten, jedoch niemals mehr als ein paar Tausend. Dies ist ein guter Anwendungsfall für die Referenzierung. Sie würden die ObjectIDs der Teile in ein Array im Produktdokument einfügen.

Eins-zu-Billionen

Ein Beispiel für "Eins-zu-Billionen" könnte ein Ereignisprotokollierungssystem sein, das Protokollnachrichten für verschiedene Computer sammelt. Jeder Host kann genügend Nachrichten generieren, um die Dokumentgröße von 16 MB zu überschreiten, selbst wenn Sie nur die ObjectID im Array gespeichert haben. Dies ist der klassische Anwendungsfall für die übergeordnete Referenzierung. Sie haben ein Dokument für den Host und speichern dann die ObjectID des Hosts in den Dokumenten für die Protokollnachrichten.

Bmaupin
quelle
11

Dokumente, die im Laufe der Zeit erheblich wachsen, können Zeitbomben sein. Netzwerkbandbreite und RAM-Auslastung werden wahrscheinlich zu messbaren Engpässen, die Sie dazu zwingen, von vorne zu beginnen.

Betrachten wir zunächst zwei Sammlungen: Kunde und Zahlung. Somit ist das Korn ziemlich klein: ein Dokument pro Zahlung.

Als Nächstes müssen Sie entscheiden, wie Kontoinformationen wie Kreditkarten modelliert werden sollen. Lassen Sie uns überlegen, ob Kundendokumente Arrays von Kontoinformationen enthalten oder ob Sie eine neue Kontosammlung benötigen.

Wenn Kontodokumente von Kundendokumenten getrennt sind, müssen zum Laden aller Konten für einen Kunden mehrere Dokumente abgerufen werden. Dies kann zu zusätzlichem Speicher, E / A, Bandbreite und CPU-Auslastung führen. Bedeutet das sofort, dass die Kontosammlung eine schlechte Idee ist?

Ihre Entscheidung wirkt sich auf Zahlungsbelege aus. Wenn Kontoinformationen in ein Kundendokument eingebettet sind, wie würden Sie darauf verweisen? Separate Kontodokumente haben ein eigenes _id-Attribut. Mit eingebetteten Kontoinformationen generiert Ihre Anwendung entweder neue IDs für Konten oder verwendet die Attribute des Kontos (z. B. Kontonummer) für den Schlüssel.

Könnte ein Zahlungsbeleg tatsächlich alle Zahlungen enthalten, die innerhalb eines festgelegten Zeitrahmens (z. B. Tag?) Getätigt wurden? Diese Komplexität wirkt sich auf den gesamten Code aus, der Zahlungsdokumente liest und schreibt. Vorzeitige Optimierung kann für Projekte tödlich sein.

Wie bei Kontodokumenten können Zahlungen leicht referenziert werden, solange ein Zahlungsdokument nur eine Zahlung enthält. Ein neuer Dokumenttyp, beispielsweise eine Gutschrift, könnte auf eine Zahlung verweisen. Aber würden Sie eine Kreditsammlung erstellen oder Kreditinformationen in Zahlungsinformationen einbetten? Was würde passieren, wenn Sie später auf eine Gutschrift verweisen müssten?

Zusammenfassend war ich mit vielen kleinen Dokumenten und vielen Sammlungen erfolgreich. Ich implementiere Referenzen mit _id und nur mit _id. Daher mache ich mir keine Sorgen, dass ständig wachsende Dokumente meine Anwendung zerstören. Das Schema ist leicht zu verstehen und zu indizieren, da jede Entität ihre eigene Sammlung hat. Wichtige Entitäten verstecken sich nicht in anderen Dokumenten.

Ich würde gerne von Ihren Erkenntnissen hören. Viel Glück!

Terris
quelle