MongoDB und PostgreSQL zusammen verwenden

25

Mein aktuelles Projekt ist im Wesentlichen ein Durchlauf des Mill Document Management Systems.

Das heißt, es gibt einige Falten (Überraschung, Überraschung). Während einige der Falten für das Projekt ziemlich spezifisch sind, glaube ich, dass es einige allgemeine Beobachtungen und Fragen gibt, die keine kanonische Antwort haben (die ich ohnehin finden könnte) und die auf ein breiteres Problemgebiet anwendbar sind . Hier gibt es eine Menge und ich bin mir nicht sicher, ob es gut zum StackExchange-Q & A-Format passt, aber ich denke, es ist a) eine beantwortbare Frage und b) nicht spezifisch genug, um der Community zu nützen. Einige meiner Überlegungen sind spezifisch für mich, aber ich denke, die Frage könnte für jeden von Nutzen sein, der sich für SQL vs. NoSQL vs. beides entscheidet.

Der Hintergrund:

Die von uns erstellte Web-App enthält Daten, die eindeutig relationaler Natur sind, sowie dokumentenorientierte Daten. Wir möchten unseren Kuchen haben und ihn auch essen.

TL; DR: Ich denke, dass # 5 unten den Geruchstest besteht. Machst du? Hat jemand Erfahrung mit einer solchen Integration von SQL und NOSQL in einer einzigen Anwendung? Ich habe versucht, alle möglichen Ansätze für diese Problemklasse im Folgenden aufzulisten. Habe ich eine vielversprechende Alternative verpasst?

Komplexitäten:

  • Es gibt viele verschiedene Klassen von Dokumenten. Die Anforderungen verlangen bereits nach Dutzenden verschiedener Dokumente. Diese Zahl wird immer nur steigen. Der bestmögliche Fall wäre ein Fall, in dem wir eine einfache domänenspezifische Sprache, Codegenerierung und ein flexibles Schema nutzen könnten, sodass Domänenexperten das Hinzufügen neuer Dokumentklassen ohne das Eingreifen von DBAs oder Programmierern handhaben könnten. (Hinweis: Wir wissen bereits, dass wir die Zehnte Regel von Greenspun einhalten. )
  • Die Integrität früherer erfolgreicher Schreibvorgänge ist eine zentrale Anforderung des Projekts. Die Daten sind geschäftskritisch. Die vollständige ACID-Semantik für Schreibvorgänge kann geopfert werden, vorausgesetzt, die Dinge, die erfolgreich geschrieben werden, bleiben geschrieben.
  • Die Dokumente selbst sind komplex. Das Prototypdokument in unserem speziellen Fall erfordert die Speicherung von mehr als 150 unterschiedlichen Datenelementen pro Dokumentinstanz. Der pathologische Fall könnte eine Größenordnung schlimmer sein, aber sicher nicht zwei.
  • Eine einzelne Dokumentenklasse ist ein sich bewegendes Ziel, das zu einem späteren Zeitpunkt aktualisiert werden muss.
  • Wir mögen die kostenlosen Sachen, die wir von Django bekommen, wenn wir sie in eine relationale Datenbank einbinden. Wir möchten die Werbegeschenke behalten, ohne zwei Django-Versionen zurückspringen zu müssen, um die Django-Nonrel-Gabel zu verwenden. Das vollständige Dumpen des ORM ist einem Downgrade auf 1.3 vorzuziehen.

Im Wesentlichen handelt es sich um eine Mischung aus relationalen Daten (Ihren typischen Web-App-Inhalten wie Benutzern, Gruppen usw.) und Dokumentdaten (z. B. Dokument-Metadaten, die in Echtzeit für komplexe Abfragen benötigt werden) Die Hunderte von Feldern, an denen wir uns nicht beteiligen oder die wir abfragen möchten - unser einziger Anwendungsfall für die Daten ist die Anzeige des einzelnen Dokuments, in das sie eingegeben wurden.

Ich wollte eine Überprüfung der Vernunft durchführen (wenn Sie meinen Posting-Verlauf überprüfen, bin ich ziemlich explizit in Bezug auf die Tatsache, dass ich kein Datenbankadministrator bin) und alle Optionen auflisten, die mir bei der Lösung durch andere begegnet sind weitgehend ähnliche Probleme mit relationalen und nicht relationalen Daten.

Vorgeschlagene Lösungen:

1. Eine Tabelle pro Dokumentenklasse

Jede Dokumentklasse erhält eine eigene Tabelle mit Spalten für alle Metadaten und Daten.

Vorteile:

  • Das Standard-SQL-Datenmodell ist im Spiel.
  • Relationale Daten werden bestmöglich behandelt. Wir werden später denormalisieren, wenn wir müssen.
  • Djangos integrierte Administrationsoberfläche ist mit dem Introspizieren dieser Tabellen vertraut, und der ORM kann mit 100% der sofort einsatzbereiten Daten zufrieden sein.

Nachteile:

  • Wartungs-Albtraum. Dutzende (Hunderte?) Tabellen mit (Zehntausenden?) Spalten.
  • Logik auf Anwendungsebene, mit der genau entschieden wird, in welche Tabelle geschrieben werden soll. Das Festlegen des Tabellennamens als Parameter für eine Abfrage stinkt.
  • Grundsätzlich erfordern alle Änderungen der Geschäftslogik Schemaänderungen.
  • In pathologischen Fällen müssen möglicherweise Daten für einzelne Formulare über mehrere Tabellen verteilt werden (siehe: Wie viele Spalten dürfen in einer PostgreSQL-Tabelle maximal enthalten sein? ).
  • Wir müssten wahrscheinlich einen echten, ehrlichen DBA finden, der zweifellos das Leben und uns hassen würde.

2. EAV-Modellierung

Es gibt nur eine Feldtabelle. Die Modellierung von Entitätsattributen und -werten ist bereits bekannt. Ich habe es der Vollständigkeit halber aufgenommen. Ich denke nicht, dass ein neues Projekt, das 2013 gestartet wird, absichtlich mit einem EAV-Ansatz einhergehen würde.

Vorteile:

  • Einfach zu modellieren.

Nachteile:

  • Schwieriger abzufragen.
  • Der DB-Layer verfügt nicht mehr über eine einfache Darstellung für ein einziges Objekt auf App-Ebene.
  • Wir würden die Einschränkungsüberprüfung auf DB-Ebene verlieren.
  • Die Anzahl der Zeilen in einer Tabelle wächst um das 100- bis 1000-fache. Wahrscheinlich zukünftiger Schmerzpunkt, was die Leistung betrifft.
  • Eingeschränkte Indizierung möglich.
  • Das DB-Schema ist für ORM unsinnig. Die im Lieferumfang der Webanwendung enthaltenen Batterien bleiben erhalten, benutzerdefinierte Datenmodelle erfordern jedoch benutzerdefinierte Abfragen.

3. Verwenden Sie PostgreSQL-Speicher oder JSON-Felder

Jeder dieser Feldtypen reicht aus, um schemenlose Daten im Kontext einer relationalen Datenbank zu speichern. Der einzige Grund , warum ich auf diese Lösung nicht sofort springen ist es relativ neu ist (in der Version 8.4 eingeführt , so nicht , dass neu), ich habe Null vorherige Exposition gegenüber , und ich bin misstrauisch. Es scheint mir aus genau den gleichen Gründen falsch zu sein, aus denen es mir unangenehm ist, all meine netten, leicht zu normalisierenden Daten in Mongo zu werfen - obwohl Mongo Verweise zwischen Dokumenten verarbeiten kann.

Vorteile:

  • Wir erhalten die Vorteile des Django ORM und des eingebauten Authentifizierungs- und Sitzungsmanagements.
  • Alles bleibt in einem Backend, das wir zuvor erfolgreich für andere Projekte verwendet haben.

Nachteile:

  • Keine Erfahrung damit, persönlich.
  • Es sieht nicht nach einer sehr häufig verwendeten Funktion aus. Es sieht so aus, als würden sie Leuten empfohlen, die sich mit NOSQL-Lösungen beschäftigen, aber ich sehe nicht viele Beweise dafür, dass sie ausgewählt werden. Das lässt mich denken, dass ich etwas vermissen muss.
  • Alle gespeicherten Werte sind Zeichenfolgen. Einschränkungsüberprüfung auf DB-Ebene verloren
  • Die Daten im hstore werden dem Benutzer nur angezeigt, wenn sie speziell ein Dokument anzeigen. Die in Standardspalten gespeicherten Metadaten werden jedoch angezeigt. Wir werden diese Metadaten übertreffen und ich befürchte, dass die ziemlich großen Speicher, die wir erstellen werden, mit Leistungseinbußen einhergehen könnten.

4. Gehen Sie dokumentenorientiert vor

Machen Sie alle Dinge Dokumente (im Sinne von MongoDB). Erstellen Sie eine einzelne Sammlung von Typ Documentund nennen Sie es einen Tag. Bringen Sie auch alle Peripheriedaten (einschließlich Daten zu Benutzerkonten, Gruppen usw.) in den Mongo. Diese Lösung ist offensichtlich besser als die EAV-Modellierung, aber sie fühlt sich für mich aus demselben Grund falsch an, aus dem # 3 falsch gefühlt hat - beide haben das Gefühl, Ihren Hammer auch als Schraubendreher zu verwenden.

Vorteile:

  • Daten müssen nicht im Voraus modelliert werden. Haben Sie eine Sammlung mit Dokumenten des Typs Documentund nennen Sie es einen Tag.
  • Bekannt gute Skalierungseigenschaften, sollte die Sammlung wachsen müssen, um Millionen oder sogar Milliarden von Dokumenten zu umfassen.
  • Das JSON-Format (BSON) ist für Entwickler intuitiv.
  • Soweit ich weiß (was zum jetzigen Zeitpunkt nur vage ist), kann durch die Paranoidität in Bezug auf die Schreibsicherheit selbst eine einzelne Instanz eine ziemlich starke Datensicherheit für alle Fälle bis hin zu einem Festplattencrash bieten.

Nachteile:

  • Das ORM ist aus dem Fenster für den Django-Kofferraum. Werbegeschenke, die damit aus dem Fenster gehen: das Auth-Framework, das Sessions-Framework, die Admin-Oberfläche, sicherlich viele andere Dinge.
  • Sie müssen entweder die Referenzierungsfunktionen von Mongo verwenden (für die mehrere Abfragen erforderlich sind) oder die Daten denormalisieren. Wir verlieren nicht nur Werbegeschenke, die wir von Django erhalten haben, sondern auch Werbegeschenke wie JOINs, die wir in PostgreSQL für selbstverständlich hielten.
  • Datensicherheit. Wenn man über MongoDB liest, scheint es immer mindestens eine Person zu geben, die sich darauf bezieht, wie es funktioniert und Ihre Daten verliert. Sie zitieren nie ein bestimmtes Ereignis und es könnte alles nur Schwachsinn sein oder nur mit dem alten Standardfeuer zusammenhängen und das Schreiben vergessen, aber es macht mir immer noch Sorgen. Wir werden natürlich in jedem Fall eine ziemlich paranoide Backup-Strategie anwenden (wenn Daten unbemerkt verfälscht werden, kann das natürlich auch unerheblich sein ..).

5. PostgreSQL und MongoDB

Relationale Daten werden in die relationale Datenbank und Dokumentdaten in die dokumentorientierte Datenbank verschoben. Die documentsTabelle in der relationalen Datenbank enthält alle Daten, die wir möglicherweise zum Indizieren oder Schneiden und Würfeln benötigen, sowie eine MongoDB-Objekt-ID, die wir verwenden würden, wenn wir die tatsächlichen Werte der Felder in den Dokumenten abfragen müssten. Wir wären nicht in der Lage, das ORM oder den eingebauten Admin für die Werte der Dokumente selbst zu verwenden, aber das ist kein großer Verlust, da die gesamte App im Grunde eine Administrationsoberfläche für die Dokumente ist und wir wahrscheinlich mussten Passen Sie diesen bestimmten Teil des ORM in nicht akzeptablem Maße an, damit er genau so funktioniert, wie wir ihn benötigen.

Vorteile:

  • Jedes Backend macht nur das, wozu es gut ist.
  • Referenzen zwischen Modellen werden beibehalten, ohne dass mehrere Abfragen erforderlich sind.
  • Wir dürfen die Batterien behalten, die uns Django für Benutzer, Sitzungen usw. gegeben hat.
  • Sie benötigen nur eine documentsTabelle, unabhängig davon, wie viele verschiedene Dokumentenklassen erstellt werden.
  • Die weniger häufig abgefragten Dokumentdaten sind stark von den weitaus häufiger abgefragten Metadaten getrennt.

Nachteile:

  • Das Abrufen von Dokumentdaten erfordert zwei aufeinanderfolgende Abfragen, zuerst für die SQL-Datenbank und dann für die MongoDB (obwohl dies nicht schlimmer ist, als wenn dieselben Daten in Mongo gespeichert und nicht denormalisiert wurden).
  • Schreiben wird nicht mehr atomar sein. Ein Schreibvorgang gegen ein einzelnes Mongo-Dokument ist garantiert atomar, und PG kann natürlich Atomizitätsgarantien abgeben, aber um sicherzustellen, dass beide Schreibvorgänge atomar sind, ist eine Anwendungslogik erforderlich, ohne Zweifel mit einem Leistungs- und Komplexitätsverlust.
  • Zwei Backends = zwei Abfragesprachen = zwei verschiedene Programme mit unterschiedlichen Administratoranforderungen = zwei Datenbanken, die um Speicher wetteifern.
Chucksmash
quelle
Ich würde für eine Spalte mit einem JSONDatentyp gehen. Haben Sie keine Angst davor, neue Funktionen in Postgres zu verwenden - das Postgres-Team veröffentlicht keine Funktionen, die nicht stabil sind. Und 9.2 ist eigentlich nicht so neu). Außerdem können Sie die neuen JSON-Funktionen in 9.3 nutzen, sobald diese verfügbar sind. Wenn Sie die Dokumente in Ihrem Anwendungscode immer vollständig verarbeiten (anstatt SQL zu verwenden), können Sie JSON auch in einer regulären textSpalte speichern .
a_horse_with_no_name
An potenzielle Antwortende: Bitte geben Sie eine Antwort! Da diese Frage ohne eine "perfekte" Antwort ziemlich lange überlebt hat, beabsichtige ich, die Frage mit einem vollständigen Postmortem der Erfahrung zu beantworten, sobald wir sie implementiert und in die Produktion übergegangen sind. Es könnte ein Jahr in der Zukunft sein, aber keine Sorge - OP wird liefern. Ich gehe davon aus, dass dies für diejenigen, die diese spezielle Frage favorisiert / befürwortet haben, am nützlichsten ist: die Überprüfung, ob sie funktioniert, oder eine Erklärung, welche Straßensperren die Side-by-Side-Option getötet haben.
Chucksmash
2
@chucksmash. Bist du immerhin mit # 5 gefahren? Wie haben Sie es geschafft, beide DBS zu implementieren? Welche Tools haben Sie verwendet? Wenn nein, warum?
Xpanta
@chucksmash Ich warte immer noch auf das versprochene Feedback.
Bhashit Parikh
@ Chucksmash OP nicht geliefert ... :(
Albert Rothman

Antworten:

13

Einige Gedanken....

Normalerweise möchte man keine eng miteinander verknüpften Informationen in verschiedenen Systemen speichern. Die Wahrscheinlichkeit, dass Dinge nicht mehr synchron sind, ist hoch. Statt eines Problems haben Sie jetzt zwei. Eine Sache, die Sie mit Mongo tun können, ist, Ihre Daten ein- oder auszukoppeln. Ich bevorzuge es, alles in PostgreSQL zu belassen, soweit dies möglich ist. Ich möchte jedoch darauf hinweisen, dass dies wirklich Expertenwissen in der PostgreSQL-Programmierung erfordert und nicht für Geschäfte gedacht ist, die sich nicht der Verwendung erweiterter Funktionen widmen möchten. Ich sehe etwas andere Optionen als Sie. Da meine Präferenz nicht in einer Liste aufgeführt ist, werde ich sie Ihnen geben.

Sie können Ihre Metadaten wahrscheinlich in allgemeine Daten, für Klassen erforderliche Daten und Dokumentdaten aufteilen. In dieser Hinsicht hätten Sie eine allgemeine Katalogtabelle mit den grundlegenden allgemeinen Informationen sowie eine Tabelle pro Klasse. In dieser Tabelle würden Sie ein hstore-, json- oder xml-Feld haben, in dem der Rest der Daten zusammen mit Spalten gespeichert wird, in denen Sie Daten speichern, die erheblich eingeschränkt werden müssen. Dies würde das reduzieren, was Sie in diese Tabellen pro Klasse einfügen müssen, würde es Ihnen jedoch ermöglichen, Einschränkungen zu nutzen, wie Sie möchten. Die drei Optionen haben unterschiedliche Probleme und sollten separat betrachtet werden:

hstore ist relativ begrenzt, wird aber auch von vielen Leuten genutzt. Es ist nicht sehr neu, aber es ist nur ein Schlüssel- / Wertspeicher und im Gegensatz zu json und xml nicht in der Lage, verschachtelte Datenstrukturen zu erstellen.

json ist ziemlich neu und macht momentan nicht viel. Das bedeutet nicht, dass Sie nicht viel damit anfangen können, aber Sie werden nicht viel außerhalb der Box anfangen. Wenn Sie dies tun, können Sie damit rechnen, einen erheblichen Programmieraufwand zu erbringen, wahrscheinlich in plv8js oder, wenn Sie in älteren Umgebungen bleiben möchten, in plperlu oder plpython. jsonwird in 9.3 besser unterstützt, obwohl dies zumindest in aktuellen Entwicklungs-Snapshots der Fall ist. Mit der Veröffentlichung dieser Version wird es also besser.

xml wird am besten unterstützt, mit den meisten Funktionen und dem längsten Supportverlauf. Andererseits ist es XML .....

Wenn Sie sich jedoch für Mongo und PostgreSQL zusammen entscheiden, beachten Sie, dass PostgreSQL 2-Phasen-Commit unterstützt, dh, Sie können die Schreibvorgänge ausführen, PREPARE TRANSACTIONund wenn dies erfolgreich ist, führen Sie Ihre atomaren Schreibvorgänge in Mongo aus. Wenn das gelingt kannst du COMMITin PostgreSQL.

Chris Travers
quelle
1
Dies sind alles gute Vorschläge. Ich hatte bereits erwähnt, dass ich hstore / json verwende (und hatte stillschweigend xml abgezinst, weil ja, xml), aber ich hatte nicht daran gedacht, sie so zu verwenden, wie Sie es empfehlen. Darüber hinaus lautet der Vorschlag für ein Postgres 2-Phase-Commit Gold. Ich hatte keine Ahnung, dass es das gibt. Danke für die tollen Vorschläge.
Chucksmash
Das zweistufige Commit ist wirklich Gold. Dies macht die gleichzeitige Verwendung von NoSQL sehr einfach. Vor allem, wenn sich die Daten zwischen den beiden
DBs
0

Sie können eine Abfrage-Engine wie Presto oder Dremio einrichten , um Daten in MongoDB und Postgres mit einer einzigen Abfrage zu verknüpfen . Beide haben Konnektoren für jede dieser Datenbanken (siehe die Dokumente hier und hier ) und schlagen vor, "SQL auf irgendetwas" auszuführen bzw. "irgendetwas zusammenfügen".

Zum Testen von Presto können Sie einen kleinen Cluster in AWS EMR mit Hadoop, Hive und Presto bereitstellen (Farbton hinzufügen, wenn Sie die Befehlszeile nicht verwenden möchten). Befolgen Sie zum Einrichten diese Anweisungen die Anschlüsse . Hive ist nicht unbedingt erforderlich, aber damit können Sie Tabellen mit dem Ergebnis von Verknüpfungen zwischen Mongo und Postgres erstellen (Beispiele finden Sie auf dieser Seite ). Es gibt auch eine kostenpflichtige Version auf dem Markt , die (angeblich) stark optimiert ist und eine 30-Tage-Testversion bietet.

Ich habe Dremio noch nicht verwendet, aber es gibt auch einige einfache Möglichkeiten, es in AWS, Azure oder vor Ort bereitzustellen . Sie haben einige Online-Kurse auf ihrer Website , mit Zugang zu einem "virtuellen Labor", in dem Sie die Kurse kostenlos verfolgen können.

kadu
quelle