Datenbankdesign - Speicherstatus oder Berechnungsstatus jedes Mal?

17

Angenommen, ich habe eine relationale Datenbankanwendung und ein "Benutzer" -Objekt und ein "Nachrichten" -Objekt. Jetzt möchte ich die Anzahl der ungelesenen Nachrichten für diesen Benutzer anzeigen.

Wie archiviere ich das am besten? Füge ich ein Feld in den Benutzer ein und zähle es hoch, wenn der Benutzer eine Nachricht erhält, und verringere die Anzahl, wenn er eine liest? Oder führe ich jedes Mal eine Abfrage durch, um die Anzahl der Nachrichten für den Benutzer zu berechnen, die als ungelesen markiert sind?

Ich denke, der erste Ansatz ist komplizierter und fehleranfälliger, bietet aber eine bessere Leistung als der zweite Ansatz.

Wie wird das normalerweise gemacht oder was ist der bessere Ansatz?

jan
quelle
1
Hängt von einer Reihe von Faktoren ab: Ist Ihre DB partitioniert? Wie viele Zeilen / Benutzer erwarten Sie? Welche Gesamtgröße der Datenbank erwarten Sie (oder wie viele Benutzer insgesamt)? Mit wie vielen Anfragen pro Sekunde rechnen Sie? All dies muss nicht genau sein, aber einige grobe Ideen ...
Omer Iqbal
10
+1 Dies ist eine klassische relationale Datenbankfrage. Normalisieren oder nicht normalisieren? Das ist hier die Frage. Ob es in dem Schema edler ist, die Schleudern und Pfeile der unerhörten Vervielfältigung zu erleiden, oder die Auslöser aufzugreifen und sie durch Anwenden zu beenden?
Ross Patterson
Ich argumentiere, ob dies ein klassisches Rel ist. db. Frage, es sollte bereits eine Antwort auf der Site geben, diese sollte als DUP geschlossen sein, oder wir haben keine Antwort und diese sollte offen bleiben.
Mattnz

Antworten:

14

Wie wird das normalerweise gemacht oder was ist der bessere Ansatz?

Am besten probieren Sie es zuerst ohne zusätzliches Feld aus, messen die Leistung und wenn es sich wirklich als zu langsam herausstellt, versuchen Sie zu optimieren. Dies kann bedeuten, dass Sie mit einem zusätzlichen Feld zu Ihrem ersten Ansatz wechseln. Sie sollten jedoch auch andere Optionen testen, z. B. einen zusätzlichen Index für die kombinierten Felder ("ungelesen", "Benutzer-ID") in Ihren Nachrichten.

Doc Brown
quelle
2
Der beste Ansatz ist (zuerst mit der einfacheren Methode). Allgemeine Regeln sind besser als Besonderheiten, fwiw. (+1 für "Test!")
DougM
9

Die Lehrbuchlösung nach der Datenbanktheorie würde darin bestehen, keine Werte in Ihrer Datenbank zu haben, die von den Werten anderer Daten abhängen, da dies transitive Abhängigkeiten sind . Das Vorhandensein von Feldern, bei denen es sich um berechnete Werte handelt, die auf anderen Feldern basieren, stellt eine Verletzung der Normalisierung dar, da dies zu redundanten Informationen führt.

Manchmal unterscheiden sich jedoch die Aussagen des Lehrbuchs und die praktischste Methode in der Praxis. Das Zählen der Anzahl ungelesener Nachrichten pro Seitenaufruf kann eine ziemlich teure Operation sein. Das userCachen der Nummer in der -Tabelle wäre für die Leistung viel besser. Dies kann zu Inkonsistenzen in der Datenbank führen: Es kann vorkommen, dass eine Nachricht gelöscht, hinzugefügt oder gelesen wird, ohne dass der ungelesene Zähler aktualisiert werden muss.

Philipp
quelle
4
Das Konsistenzproblem lässt sich leicht mit Triggern lecken, die den Zähler auf INSERToder einstellen DELETE. (Oder um UPDATEzu berücksichtigen, dass sich der Besitzer einer Nachricht ändert.) Ein gutes DBMS führt die Operation aus und führt die Trigger in derselben Transaktion aus, sodass entweder alle oder keine davon auftreten.
Blrfl
4

Das potenzielle Problem ist die Leistung, und Sie haben noch kein Leistungsproblem. Abhängig von der Datenbank Ihrer Wahl können Sie in Lösung 1 viele Dinge tun: Indizieren, Hardware, Zwischenspeichern usw. Dies alles hängt davon ab, wie oft der Benutzer eine aktuelle Anzahl ungelesener Nachrichten abrufen muss. Viele dieser Optionen erfordern keine benutzerdefinierte Codierung auf der App-Seite, sodass Sie sie mit einer Codeänderung oder mit sehr wenig Code implementieren können. Erleichtert das Wachsen mit der App.

Sobald ein Benutzer eine Verbindung herstellt oder sich anmeldet, ist es nicht so schlimm, die Anzahl einmal aus der Datenbank abzurufen. Wird Ihre App eine ständig aktualisierte Liste von Nachrichten wie E-Mails führen? Wenn Sie von hier aus eine ungelesene Anzahl abrufen möchten, müssen Sie keinen weiteren Trip in die Datenbank durchführen. Wenn Sie neue Nachrichten abrufen möchten, müssen Sie trotzdem einen DB-Trip durchführen.

Machen Sie jedes Mal eine Reise zur Datenbank, wenn eine Nachricht gelesen wird, um das IsRead zu kennzeichnen? Feld ist genug ohne Neuberechnung eines anderen Feldes.

Benötigen Sie bei Lösung Nr. 2 (Aufzeichnen einer Anzahl in einem Feld / auf einem Datenträger) eine Routine, um dieses Feld bei einem Problem regelmäßig neu aufzubauen / neu zu berechnen? Und es gibt immer Probleme. Wirst du all dies in eine Transaktion einwickeln? Jedes Mal, wenn jemand einer anderen Person eine Nachricht sendet, kann dies fehlschlagen, da der UnreadCount des empfangenden Benutzers aufgrund einer Sperre der Benutzertabelle nicht aktualisiert werden kann. Oder erstellen Sie eine separate Tabelle für dieses Feld?

JeffO
quelle
+1 für das Erwähnen der Leistungsprobleme beim
Aktualisieren der Zählfelder
0

Ich würde es tun, indem ich jedes Mal eine Abfrage ausführe, also Ihren zweiten Ansatz. Stellen Sie einfach sicher, dass Sie in Ihrer Nachrichtentabelle einen Index für die Spalte hinzufügen, die als Fremdschlüssel für die Benutzertabelle fungiert, um die Leistung Ihrer Abfrage zu verbessern.

Messen Sie dann, wie der Arzt sagt, die Leistung dieses Ansatzes, und Sie werden feststellen können, ob Sie einen anderen Weg einschlagen müssen.

Jose B
quelle