2010-06-14 16 views
70

Hintergrund
Ich entwickle eine Konvertierung von unserer RDBMS-Datenbank zu MongoDB. Während der Denormalisierung scheint es, als hätte ich zwei Möglichkeiten, eine, die zu vielen (Millionen) kleinerer Dokumente führt oder zu weniger (hunderttausenden) großen Dokumenten führt.MongoDB Schema Design - Viele kleine Dokumente oder weniger große Dokumente?

Wenn ich es auf eine einfache analoge destillieren könnte, wäre es der Unterschied zwischen einer Sammlung mit weniger Kundendokumente wie folgt aus (in Java) sein:

 
class Customer { 
    private String name; 
    private Address address; 
    // each CreditCard has hundreds of Payment instances 
    private Set<CreditCard> creditCards; 
} 

oder eine Sammlung mit vielen, Dokumente viele Zahlungs dies wie:

 
class Payment { 
    private Customer customer; 
    private CreditCard creditCard; 
    private Date payDate; 
    private float payAmount; 
} 

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

Ich habe mich viel umgeschaut, aber ich stolperte in keine MongoDB Schema Best Practices, die helfen würden ich beantworte meine Frage.

Antwort

71

Sie werden auf jeden Fall für die Abfragen optimieren müssen Sie tun.

Hier ist meine beste Vermutung auf Ihrer Beschreibung basiert.

Sie möchten wahrscheinlich alle Kreditkarten für jeden Kunden kennen, also behalten Sie eine Reihe von diesen innerhalb des Kundenobjekts. Wahrscheinlich möchten Sie auch eine Kundenreferenz für jede Zahlung haben. Dadurch wird das Zahlungsdokument relativ klein gehalten.

Das Objekt Zahlung wird automatisch eine eigene ID und Index haben. Wahrscheinlich möchten Sie auch einen Index zur Kundenreferenz hinzufügen.

Damit können Sie schnell nach Zahlungen nach Kunden suchen, ohne jedes Mal das gesamte Kundenobjekt zu speichern.

Wenn Sie Fragen beantworten möchten wie "Was war der durchschnittliche Betrag, den alle Kunden im letzten Monat bezahlt haben" werden Sie stattdessen eine Karte/reduzieren für jede größere Datenmenge wollen. Sie erhalten diese Antwort nicht "in Echtzeit". Sie werden feststellen, dass das Speichern einer "Referenz" für den Kunden wahrscheinlich gut genug für diese Map-Reduzierungen ist.

So, um Ihre Frage direkt zu beantworten: Ist MongoDB entworfen, um viele, viele kleine Dokumente oder weniger große Dokumente zu bevorzugen?

MongoDB wurde entwickelt, um indizierte Einträge sehr schnell zu finden. MongoDB ist sehr gut darin, eine paar Nadeln in einem großen Heuhaufen zu finden. MongoDB ist nicht sehr gut zu finden am meisten der Nadeln im Heuhaufen. Erstellen Sie Ihre Daten also in den gängigsten Anwendungsfällen und schreiben Sie Map-/Reduce-Jobs für seltenere Anwendungsfälle.

5

Dokumente, die im Laufe der Zeit erheblich wachsen, können tickende Zeitbomben sein. Die Netzwerkbandbreite und die RAM-Nutzung werden wahrscheinlich zu messbaren Engpässen führen, sodass Sie von vorn beginnen müssen.

Zunächst betrachten wir zwei Sammlungen: Kunde und Zahlung. Daher ist das Getreide ziemlich klein: ein Dokument pro Zahlung.

Als nächstes müssen Sie entscheiden, wie Kontoinformationen modelliert werden, z. B. Kreditkarten. Stellen wir uns vor, ob Kundendokumente Felder mit Kontoinformationen enthalten oder ob Sie eine neue Kontosammlung benötigen.

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

Ihre Entscheidung betrifft Zahlungsbelege. Wenn Kontoinformationen in ein Kundendokument eingebettet sind, wie würden Sie darauf verweisen? Gesonderte Konto-Dokumente haben ihr eigenes _id-Attribut. Mit eingebetteten Kontoinformationen würde Ihre Anwendung entweder neue IDs für Konten generieren oder die Kontoattribute (z. B. Kontonummer) für den Schlüssel verwenden.

Könnte ein Zahlungsbeleg tatsächlich alle Zahlungen enthalten, die in einem festen Zeitrahmen (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 Zahlungsbeleg nur eine Zahlung enthält. Ein neuer Dokumenttyp, beispielsweise ein Kredit, könnte auf eine Zahlung verweisen. Aber würden Sie eine Kreditsammlung erstellen oder würden Sie Kreditinformationen in Zahlungsinformationen einbetten? Was würde passieren, wenn Sie später auf einen Kredit verweisen müssten?

Zusammenfassend war ich erfolgreich mit vielen kleinen Dokumenten und vielen Sammlungen. Ich implementiere Referenzen mit _id und nur mit _id. Daher mache ich mir keine Sorgen über ständig wachsende Dokumente, die meine Bewerbung 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 über Ihre Ergebnisse hören. Viel Glück!

9

Laut MongoDB eigenen Dokumentation klingt es wie es für viele kleine Dokumente konzipiert ist.

Von Performance Best Practices for MongoDB:

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

Von 6 Rules of Thumb for MongoDB Schema Design: Part 1:

Modellierung One-to-Few

Ein Beispiel für „one-to-few“ könnten die Adressen für eine Person sein. Diese ist ein guter Anwendungsfall für die Einbettung - Sie würden die Adressen in ein Array innerhalb Ihres Person-Objekts setzen.

One-to-Many

Ein Beispiel für „one-to-many“ könnte sein, Teile für ein Produkt in einem Ersatzteil-Bestellsystem. Jedes Produkt kann bis zu mehreren hundert Ersatzteilen, aber nie mehr als ein paar tausend oder so haben. Dies ist ein guter Anwendungsfall für die Referenzierung - Sie würden die ObjectIDs die Teile in ein Array im Produktdokument einfügen.

One-to-squillions

Ein Beispiel für „one-to-squillions“ könnte ein Ereignisprotokollierung System sein, die für die Log-Meldungen verschiedene Maschinen sammeln. Jeder gegebene Host könnte genug Nachrichten erzeugen, um die 16 MB-Dokumentgröße, , zu überfließen, selbst wenn Sie im ObjectID alles im Array gespeichert haben. Dies ist der klassische Anwendungsfall für "Elternreferenzierung" - Sie haben ein Dokument für den Host, und speichern Sie dann die ObjectID des Hosts in den Dokumenten für die Protokollmeldungen.

Verwandte Themen