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 Document
und 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
Document
und 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 documents
Tabelle 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
documents
Tabelle, 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.
JSON
Datentyp 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ärentext
Spalte speichern .