Zu viel Datenvervielfältigung in Mongodb?


73

Ich bin neu in diesem ganzen NOSQL-Zeug und war kürzlich fasziniert von mongoDB. Ich erstelle eine neue Website von Grund auf neu und habe mich für MONGODB / NORM (für C #) als meine einzige Datenbank entschieden. Ich habe viel darüber gelesen, wie Sie Ihre Dokumentmodelldatenbank richtig gestalten können, und ich denke, dass mein Entwurf größtenteils ziemlich gut funktioniert hat. Ich bin ungefähr 6 Monate in meiner neuen Site und sehe allmählich Probleme mit der Vervielfältigung / Synchronisierung von Daten, mit denen ich mich immer wieder befassen muss. Nach dem, was ich gelesen habe, wird dies im Dokumentmodell erwartet, und für die Leistung ist es sinnvoll. IE Sie kleben eingebettete Objekte in Ihr Dokument, damit es schnell gelesen werden kann - keine Verknüpfungen; Aber natürlich kann man nicht immer einbetten, also hat Mongodb dieses Konzept einer DbReference, das im Grunde analog zu einem Fremdschlüssel in relationalen DBs ist.

Hier ist ein Beispiel: Ich habe Benutzer und Ereignisse; Beide erhalten ihr eigenes Dokument. Benutzer nehmen an Veranstaltungen teil. Bei Veranstaltungen haben Benutzer Teilnehmer. Ich habe beschlossen, eine Liste von Ereignissen mit begrenzten Daten in die Benutzerobjekte einzubetten. Ich habe eine Liste von Benutzern auch als "Teilnehmer" in die Ereignisobjekte eingebettet. Das Problem hier ist jetzt, dass ich die Benutzer mit der Liste der Benutzer synchron halten muss, die auch in das Ereignisobjekt eingebettet ist. Während ich es lese, scheint dies der bevorzugte Ansatz und die NOSQL-Methode zu sein. Das Abrufen ist schnell, aber der Fallback ist, wenn ich das Hauptbenutzerdokument aktualisiere. Ich muss auch in die Ereignisobjekte gehen, möglicherweise alle Verweise auf diesen Benutzer finden und diese ebenfalls aktualisieren.

Die Frage, die ich habe, ist also, ob dies ein ziemlich häufiges Problem ist, mit dem sich die Leute befassen müssen. Wie viel muss dieses Problem passieren, bevor Sie sagen "Vielleicht passt die NOSQL-Strategie nicht zu dem, was ich hier versuche"? Wann wird der Leistungsvorteil, keine Verknüpfungen durchführen zu müssen, zu einem Nachteil, da es schwierig ist, Daten in eingebetteten Objekten synchron zu halten und dafür mehrere Lesevorgänge in der Datenbank durchzuführen?


Hier ist eine weitere Frage zur Datenredundanz in MongoDB . Meine Antwort dort schlägt vor, die Ausgabe mit Kartenreduzierung als Cache anstelle einer separaten Caching-Ebene zu verwenden. Dies kann nützlich sein, wenn Sie mit veralteten Daten leben können. Beachten Sie, dass die Aktualität der Daten davon abhängt, wie oft Sie den Job zur Kartenreduzierung ausführen, z. B. alle 15 Minuten.
Niels van der Rest

DBReference ist böse, es nimmt den größten Teil des NoSQL-Charmes weg
Rahul Kumar

Antworten:


61

Nun, das ist der Kompromiss mit Dokumentenspeichern. Sie können wie jedes Standard-RDMS normalisiert speichern und sollten sich so weit wie möglich um eine Normalisierung bemühen. Nur dort, wo die Leistung beeinträchtigt wird, sollten Sie die Normalisierung aufheben und Ihre Datenstrukturen reduzieren. Der Kompromiss ist die Leseeffizienz gegenüber den Aktualisierungskosten.

Mongo verfügt über wirklich effiziente Indizes, die die Normalisierung wie bei einem herkömmlichen RDMS vereinfachen können (die meisten Dokumentenspeicher bieten diese nicht kostenlos an, weshalb Mongo eher ein Hybrid als ein reiner Dokumentenspeicher ist). Auf diese Weise können Sie eine Beziehungssammlung zwischen Benutzern und Ereignissen erstellen. Es ist analog zu einer Ersatztabelle in einem tabellarischen Datenspeicher. Indizieren Sie die Ereignis- und Benutzerfelder, und es sollte ziemlich schnell gehen und Ihnen helfen, Ihre Daten besser zu normalisieren.

Ich möchte die Effizienz des Abflachens einer Struktur darstellen, anstatt sie normal zu halten, wenn es um die Zeit geht, die ich zum Aktualisieren von Datensatzdaten benötige, und das Auslesen der Anforderungen in einer Abfrage. Sie können es in Bezug auf die große O-Notation tun, aber Sie müssen nicht so schick sein. Schreiben Sie einfach einige Zahlen auf Papier, basierend auf einigen Anwendungsfällen mit unterschiedlichen Modellen für die Daten, und bekommen Sie ein gutes Gefühl dafür, wie viel Arbeit erforderlich ist.

Grundsätzlich versuche ich zunächst, die Wahrscheinlichkeit vorherzusagen, wie viele Aktualisierungen ein Datensatz haben wird und wie oft er gelesen wird. Dann versuche ich vorherzusagen, wie hoch die Kosten für ein Update im Vergleich zu einem Lesevorgang sind, wenn es sowohl normalisiert als auch abgeflacht ist (oder vielleicht eine teilweise Kombination der beiden, die ich mir vorstellen kann ... viele Optimierungsoptionen). Ich kann dann die Einsparungen bei der Aufbewahrung im Vergleich zu den Kosten für den Aufbau der Daten aus normalisierten Quellen beurteilen. Sobald ich alle Variablen geplottet habe und die Ersparnisse, sie flach zu halten, mir eine Menge sparen, werde ich sie flach halten.

Einige Tipps:

  • Wenn Sie schnelle Suchvorgänge benötigen, um schnell und atomar zu sein (perfekt auf dem neuesten Stand), möchten Sie möglicherweise eine Lösung bevorzugen, bei der Sie es vorziehen, die Normalisierung zu reduzieren und den Erfolg des Updates zu erzielen.
  • Wenn Sie ein schnelles Update und einen sofortigen Zugriff benötigen, bevorzugen Sie die Normalisierung.
  • Wenn Sie schnelle Suchvorgänge benötigen, aber keine perfekt aktuellen Daten benötigen, sollten Sie Ihre normalisierten Daten in Stapeljobs erstellen (möglicherweise mithilfe von Map / Reduce).
  • Wenn Ihre Abfragen schnell sein müssen und Updates selten sind und nicht unbedingt ein sofortiger Zugriff auf Ihr Update erforderlich ist oder eine Sperre auf Transaktionsebene erforderlich ist, die 100% der Zeit durchlaufen wurde (um sicherzustellen, dass Ihr Update auf die Festplatte geschrieben wurde), haben Sie Sie können Ihre Aktualisierungen in eine Warteschlange schreiben, die sie im Hintergrund verarbeitet. (In diesem Modell müssen Sie sich wahrscheinlich später mit Konfliktlösung und Versöhnung befassen.)
  • Profilieren Sie verschiedene Modelle. Erstellen Sie in Ihrem Code eine Abstraktionsschicht für Datenabfragen (in gewisser Weise wie ein ORM), damit Sie Ihre Datenspeicherstruktur später umgestalten können.

Es gibt viele andere Ideen, die Sie anwenden können. Es gibt viele großartige Online-Blogs, die wie highscalabilty.org darauf eingehen und sicherstellen, dass Sie den CAP-Satz verstehen.

Berücksichtigen Sie auch eine Caching-Ebene wie Redis oder Memcache. Ich werde eines dieser Produkte vor meine Datenschicht stellen. Wenn ich Mongo abfrage (das alles normalisiert speichert), verwende ich die Daten, um eine abgeflachte Darstellung zu erstellen und sie im Cache zu speichern. Wenn ich die Daten aktualisiere, mache ich alle Daten im Cache ungültig, die auf das verweisen, was ich aktualisiere. (Obwohl Sie sich die Zeit nehmen müssen, um Daten ungültig zu machen und Daten im Cache zu verfolgen, der unter Berücksichtigung Ihrer Skalierungsfaktoren aktualisiert wird). Jemand sagte einmal: "Die zwei schwierigsten Dinge in der Informatik sind das Benennen von Dingen und die Ungültigmachung des Caches."

Hoffentlich hilft das!


Danke für die Antwort! viele gute Einblicke / Ratschläge! Ich habe nicht an die User-Event-Relations-Sammlung gedacht. und Caching wird definitiv etwas sein, das ich in Zukunft berücksichtigen muss.
Mike

+1 für die Einführung einer Ersatztabelle. Dies führt zu einem einzigen Ort, an dem Beziehungen zwischen Dokumenten definiert werden, anstatt zu zwei. @mike: Ich möchte darauf hinweisen, dass DBRef nur eine formale Spezifikation ist, es ist nicht magisch wie Fremdschlüssel :) Referenzen müssen ebenso wie doppelte Daten manuell gepflegt werden. Daher würde ich Ihnen nicht raten, "so viel wie möglich nach Normalisierung zu streben".
Niels van der Rest

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.