Verschachtelte Entitäten und Berechnung der Eigenschaft "Blattentität" - SQL- oder NoSQL-Ansatz


10

Ich arbeite an einem Hobbyprojekt namens Menü- / Rezeptverwaltung.

So sehen meine Wesenheiten und ihre Beziehungen aus.

A Nutrienthat Eigenschaften CodeundValue

An Ingredienthat eine Sammlung vonNutrients

A Recipehat eine Sammlung von Ingredientsund kann gelegentlich eine Sammlung von anderen habenrecipes

A Mealhat eine Sammlung von RecipesundIngredients

A Menuhat eine Sammlung vonMeals

Die Beziehungen können dargestellt werden als

Menüeinheiten und Beziehungen

Auf einer der Seiten muss ich für ein ausgewähltes Menü die Informationen zu den wirksamen Nährstoffen anzeigen, die anhand der Bestandteile (Mahlzeiten, Rezepte, Zutaten und die entsprechenden Nährstoffe) berechnet wurden.

Ab sofort verwende ich SQL Server zum Speichern der Daten und navigiere die Kette von meinem C # -Code aus, beginnend mit jeder Mahlzeit des Menüs und aggregiere dann die Nährstoffwerte.

Ich denke, dies ist kein effizienter Weg, da diese Berechnung jedes Mal durchgeführt wird, wenn die Seite angefordert wird und sich die Bestandteile gelegentlich ändern.

Ich habe darüber nachgedacht, einen Hintergrunddienst zu haben, der eine Tabelle mit dem Namen MenuNutrients ( {MenuId, NutrientId, Value}) verwaltet und diese Tabelle mit den wirksamen Nährstoffen füllt / aktualisiert, wenn sich eine der Komponenten (Mahlzeit, Rezept, Zutat) ändert.

Ich bin der Meinung, dass eine GraphDB gut zu dieser Anforderung passt, aber meine Exposition gegenüber NoSQL ist begrenzt.

Ich möchte wissen, was die alternativen Lösungen / Ansätze für diese Anforderung sind, die Nährstoffe eines bestimmten Menüs anzuzeigen.

Hoffe, meine Beschreibung des Szenarios ist klar.


Wie viele Objekte sprechen wir? Wird Leistung wirklich ein Problem sein?
Flup

@flup Im Durchschnitt kann ein Menü 8 Mahlzeiten enthalten, jede Mahlzeit kann 2 Rezepte und 2 Zutaten enthalten, jedes Rezept kann 6-8 Zutaten enthalten.
Chandu

Sind deine Pfeile nicht in die falsche Richtung?
Branko Dimitrijevic

Haben Sie ein Beispiel für das Nerd Dinner Entity Framework gesehen?
Akash Kava

Antworten:


8

Abhängig von den Anforderungen und der Architektur gibt es möglicherweise Optionen zur Leistungsverbesserung:

  • Sie können indizierte Ansichten (matrialisiert) verwenden, um die Leseleistung auf RDBMS-Ebene (SQL Server) zu verbessern .
    Grundsätzlich müssen Sie lediglich:
    Eine reguläre Ansicht erstellen.
    Erstellen Sie einen Clustered-Index für diese Ansicht .

  • Die Verwendung eines Einlösemechanismus auf Anwendungsebene verbessert die Leistung.
    Wenn es möglich und machbar ist, Cashing zu verwenden, hilft Ihnen eine Cash-Strategie wie Singleton Lazy Cashing .

NoSql:
Es gibt viele gute Artikel über SQL vs NoSql, so und so.

Die Teile interessieren mich:

Wo man NoSql verwendet:

Wenn Ihre Datenbank 3NF ist und Sie keine Verknüpfungen durchführen (Sie wählen nur eine Reihe von Tabellen aus und fügen alle Objekte zusammen, AKA, was die meisten Leute in einer Web-App tun.

Bei Verwendung bereit sein für:

  • Am Ende schreiben Sie Jobs, um beispielsweise Daten aus verschiedenen Tabellen / Sammlungen zusammenzufügen, was ein RDBMS automatisch für Sie tun würde.
  • Ihre Abfragefunktionen mit NoSQL sind drastisch beeinträchtigt. MongoDb ist zwar SQL am nächsten, liegt aber immer noch weit zurück. Vertrau mir. SQL-Abfragen sind sehr intuitiv, flexibel und leistungsstark. NoSql-Abfragen sind nicht.
  • MongoDb-Abfragen können Daten aus nur einer Sammlung abrufen und nur einen Index nutzen. Und MongoDb ist wahrscheinlich eine der flexibelsten NoSQL-Datenbanken. In vielen Szenarien bedeutet dies mehr Roundtrips zum Server, um verwandte Datensätze zu finden. Und dann beginnen Sie mit der De-Normalisierung von Daten - was Hintergrundjobs bedeutet.
  • Die Tatsache, dass es sich nicht um eine relationale Datenbank handelt, bedeutet, dass Sie keine Fremdschlüsseleinschränkungen haben (von einigen als schlecht angesehen), um sicherzustellen, dass Ihre Daten konsistent sind. Ich versichere Ihnen, dass dies letztendlich zu Dateninkonsistenzen in Ihrer Datenbank führen wird. Sei vorbereitet. Höchstwahrscheinlich beginnen Sie mit dem Schreiben von Prozessen oder Überprüfungen, um Ihre Datenbank konsistent zu halten. Dies ist wahrscheinlich nicht besser, als wenn das RDBMS dies für Sie erledigt.
  • Vergessen Sie ausgereifte Frameworks wie den Ruhezustand.

Neben der Entscheidung , NoSQL, einen hilfreichen Artikel über die Verwendung oder nicht verwenden NoSQL DBMS - Vergleich und die Absicht von ihnen konnte gefunden werden hier als einige von ihnen konzentrieren sich auf die hohe Lesevorgänge, geringe schreibt, karten reduzieren, HA ...
Mit einem Blick bei der Rangfolge und Popularität von ihnen kann nach Kategorie nützlich sein.


Danke für die Details. Ich werde die Links überprüfen und mich bei Ihnen melden.
Chandu

3

Ich denke, Sie müssen kein Diagramm db verwenden, sondern nur die erforderlichen Werte in einer oberen Ebene speichern. Es ist wie beim Speichern eines Orderund OrderItems. Sie müssen nicht jedes Mal die Gesamtsumme berechnen, wenn eine Bestellung angezeigt wird. Stattdessen berechnen Sie einfach Summe, Mehrwertsteuer und andere Dinge und speichern sie bei Ihnen Order.

order.Subtotal = order.Items.Sum(item => item.Price);
order.Tax = order.Subtotal * 0.25m; // just a value
order.Total = order.Subtotal + order.Tax;

// fast forward time
var subTotal = order.Items.Sum(item => item.Price);
var tax = subTotal * 0.25m;
var total = subTotal + tax;

if (toal == order.Total) {
   Console.Log("Why the hell I've just re-calculated total?");
}

3

Ich schlage vor, das Muster für die Verantwortlichkeit der Befehlsabfrage zu betrachten .

Grundsätzlich können Sie anstelle eines einzelnen Modells zum Lesen und Schreiben zwei verschiedene Modelle erstellen. Eine für die Aktualisierung und die andere für Abfragen (Lesen, Berichten, ...) optimiert. Die beiden Modelle werden mithilfe von Domänenereignissen (normalerweise mit eventueller Konsistenz) synchronisiert (siehe DDD).

Ich habe vor einigen Monaten angefangen, dieses Muster zu studieren, und es hat meine Art, Software zu modellieren, wirklich verändert. Es ist nicht einfach, weil es eine große Veränderung ist, insbesondere wenn es mit anderen Techniken wie DDD und Event Sourcing verwendet wird. Aber es lohnt sich.

Es gibt viele Ressourcen im Internet, die nach CQRS und DDD (und schließlich nach Event Sourcing) suchen.

Dieses Muster kann sowohl in SQL als auch in noSql verwendet werden.

In Ihrem Fall können Sie jedes Mal ein Ereignis auslösen, wenn die Nährstoffe geändert werden, um das Lesemodell zu aktualisieren, das für das Lesen optimiert ist. Das Lesemodell kann beispielsweise eine denormalisierte Ansicht der Nährstoffe des Menüs sein (warum nicht eine nosql-Datenbank für effizientes Lesen verwenden). Sie können mehrere Lesemodelle basierend auf den Abfragen haben, die Sie ausführen müssen.

Dieser Ansatz hat einige Auswirkungen, ist jedoch sehr skalierbar und erweiterbar.


Dies war der Ansatz, über den ich nachdachte, aber ich war mir nicht sicher, wie ich die Daten für das Lesemodell erhalten sollte (im Grunde sollte ein Prozess mir die Daten für das Lesemodell liefern).
Chandu

Normalerweise wird das Lesemodell bei jeder Änderung aktualisiert. Sie sollten die Benutzeroberfläche mit Befehlen (aufgabenbasiert) implementieren, anstatt grobe Operationen zu verwenden. Auf diese Weise wird jeder einzelne Befehl im Lesemodell wiedergegeben. Sie müssen keine anderen Abfragen ausführen. Durch das Entwerfen von Befehlen kann das System die tatsächliche Absicht des Benutzers erfassen.

2

Es hängt stark davon ab, wie Sie die Menüs und Nährstoffe anfänglich erhalten. Warum wird es Ihrer Meinung nach nicht effizient sein?

Soweit ich weiß, gehen Sie in die DB, holen sich das Menü, gehen dann noch einmal, holen sich jedes Rezept, gehen noch einmal und holen sich jede Zutat und so weiter. Dies ist wirklich ineffizient, da es viele Abfragen und Roundtrips zum Server gibt, was die Hauptursache für Verzögerungen ist. Dies ist als SELECT N + 1-Problem bekannt.

Sie sollten alle Daten in einer einzigen Abfrage abrufen, indem Sie JOINs für alle Tabellen vom Menü bis zu den Nährstoffen verwenden, damit der DB-Server alle Beziehungen und Indizes verwenden kann , um alle Daten gleichzeitig abzurufen . Die Client-C # -App verarbeitet nur das Endergebnis und zeigt es an. Dies ist viel effizienter als eins nach dem anderen.

Im Allgemeinen können relationale Datenbanken unter Verwendung geeigneter Abfragetechniken und der richtigen Indizes für kritische Abfragen unter großen Tabellen unter Last sehr gut funktionieren.


Danke, ich verstehe, dass es von den Joins abhängt. Da sich die Bestandteile des Menüs gelegentlich ändern, möchte ich die Berechnung nicht jedes Mal ausführen, wenn jemand auf die Seite gelangt. Stattdessen möchte ich, dass ein Hintergrunddienst die Berechnung durchführt, und ich kann sie bei Bedarf einfach aus einer Tabelle lesen. Das Problem bei der Berechnung besteht darin, die gesamte Kette zu identifizieren, wenn sich einer der Bestandteile ändert.
Chandu

Das Durchsuchen einiger Beziehungen führt zu keiner Berechnung, selbst wenn es 5 oder 6 JOINSekunden gibt, die den Server nicht belasten sollten (es sei denn, wir sprechen über das Abrufen von Hunderten oder Tausenden von Zeilen), wenn die Indizierung korrekt ist ist vorhanden. Selbst bei großen Datenmengen können Sie jederzeit eine Ansicht des gesamten Ergebnisses erstellen und die Ansicht sogar indizieren, um das Ergebnis vorab zu berechnen, falls die Leistung jemals zu einem Problem wird.

2

Anscheinend haben Sie einige Zeit damit verbracht, darüber nachzudenken, wie die Daten am besten modelliert werden können, damit sie leicht aktualisiert und abgefragt werden können. Jetzt sind Sie jedoch an dem Punkt angelangt, an dem Sie Zugriff auf die Daten gewähren müssen. Diese beiden Dinge sind getrennte Anliegen.

Sie erwähnen, dass das erneute Laden der Seite eine neue Abfrage in der Datenbank verursacht. Sie erwähnen auch, dass die Datenbank gelegentlich aktualisiert wird und dass diese Aktualisierungen rechtzeitig auf der Seite angezeigt werden sollen. Ihre beste Methode, um den Aufwand für Abfragen zu verringern, besteht darin, sie nicht auszuführen. Wenn Sie immer wieder dieselben Abfragen ausführen und dieselben Ergebnisse erzielen, können Sie sie für eine Weile zwischenspeichern. Sie sollten in der Lage sein, Caching im Upstream zu implementieren, ohne den Rest des Projekts zu ändern. Ich würde empfehlen, über Ruhe zu lesen. Unabhängig davon, ob Sie das Projekt in einem rdbms- oder nosql-Programm implementieren, lassen sich Probleme mit der Leistung dieses Typs am besten beheben, indem Sie die Anzahl der Aufrufe der Datenbank reduzieren. Angenommen, Sie haben in 60 Sekunden 100 Anfragen für dasselbe Rezept. Wenn Sie 60 Sekunden lang zwischenspeichern, haben Sie die Datenbank nur einmal aufgerufen, was eine 100-fache Leistungsverbesserung bedeutet. Um das gleiche Maß an Verbesserung durch den Wechsel zu nosql zu erreichen, ist viel mehr Arbeit erforderlich.

Systeme vom Typ Nosql können eine großartige Lösung sein, wenn Sie große Datenmengen oder extreme Anforderungen an die Lese- oder Schreibgeschwindigkeit haben. Diese zusätzliche Leistung geht jedoch zu Lasten der referenziellen Integrität.


1

Es scheint, als ob Sie für das Experiment oder den Wissenszweck Graph-DB ausprobieren möchten, aber Ihr Beispiel ist eindeutig ein Beispiel für hierarchische Daten, bei denen wir einen Drilldown / Up über einen Knoten durchführen können. Ich bin kein Experte für Graph / Neo DB, aber ich kann sehen, dass die Art und Weise, wie Benutzer / Sie Daten aus diesem Schema anfordern können, nicht sehr komplex ist. Ich sehe, dass die Wahl des Datenbank- / Schemadesigns sehr davon abhängt, wie und welche Art von Daten dagegen abgefragt werden. Da Sie SQLSERVER "HierarchyI" verwenden, ist D aus meiner Sicht die beste Option, um diese Knoten als Teil von Tree zu platzieren.


1

Mein Vorschlag ist, wie eine Maschine und nicht wie ein Mensch zu denken. Es mag sich wiederholen, aber was Maschinen gut können. Eine Sache, die Sie sich fragen müssen, ist: "Muss ich trotzdem jedes Objekt abrufen, um es auf meiner Seite anzuzeigen?" Wenn ja, fahren Sie fort, was Sie tun. Im Vergleich zum Abrufen von Daten sind CPU-Zyklen bei einfachen Berechnungen vernachlässigbar.

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.