Messenger-Datenbank (Teil 1): Wir entwerfen den Basisrahmen

Wie können GeschĂ€ftsanforderungen in bestimmte Datenstrukturen ĂŒbersetzt werden, indem beispielsweise eine Basis von Grund auf neu fĂŒr einen Messenger erstellt wird?



Unsere Datenbank wird nicht so groß und verbreitet sein wie die von VKontakte oder Badoo , aber "to be", aber sie ist gut - funktionsfĂ€hig, schnell und passt auf einen einzelnen PostgreSQL- Server - damit Sie beispielsweise irgendwo auf der Seite eine separate Instanz des Dienstes bereitstellen können.

Daher werden wir uns nicht mit Sharding-, Replikations- und geoverteilten Systemen befassen, sondern uns auf Schaltungslösungen in der Datenbank konzentrieren.

Schritt 1: Ein bisschen geschÀftliche SpezifitÀt


Wir werden unser Messaging nicht abstrakt gestalten, sondern in die soziale Netzwerkumgebung des Unternehmens einbetten. Das heißt, die Leute bei uns „schreiben nicht nur eine SMS“, sondern kommunizieren miteinander, um bestimmte geschĂ€ftliche Probleme zu lösen.

Und was sind die geschÀftlichen Herausforderungen? Schauen wir uns das Beispiel von Vasily an, dem Leiter der Entwicklungsabteilung.
  • "Nikolai, dieser Patch braucht diesen Patch heute!"
    Korrespondenz kann also im Kontext eines Dokuments gefĂŒhrt werden .
  • "Kolya, gehst du abends zu DotA?"
    Das heißt, auch mit einem GesprĂ€chspartnerpaar kann zu verschiedenen Themen gleichzeitig kommuniziert werden.
  • "Peter, Nikolai, schau dir den Preisaufschlag auf dem neuen Server an."
    Eine Nachricht kann also mehrere EmpfÀnger haben . In diesem Fall kann die Nachricht angehÀngte Dateien enthalten.
  • "Semyon, und du siehst auch so aus."
    Und es sollte möglich sein , ein neues Mitglied in eine bestehende Korrespondenz einzuladen .

Lassen Sie uns auf diese Liste der "offensichtlichen" BedĂŒrfnisse eingehen.
Ohne ein VerstÀndnis der angewandten Besonderheiten der Aufgabe und der von ihr festgelegten EinschrÀnkungen ist es praktisch unmöglich, ein effektives Datenbankschema zur Lösung dieser Aufgabe zu entwerfen.

Schritt 2: Minimale Logik


Bisher Àhnelt alles der E-Mail-Korrespondenz - ein traditionelles GeschÀftstool. Also ja, "algorithmisch", viele GeschÀftsaufgaben sind einander Àhnlich, und daher sind die Werkzeuge zu ihrer Lösung strukturell Àhnlich.

Lassen Sie uns das resultierende logische Diagramm der Beziehungen von EntitÀten reparieren. Um das VerstÀndnis unseres Modells zu erleichtern, verwenden wir die einfachste Methode, um ein ER-Modell ohne die Komplikationen von UML- oder IDEF-Notationen anzuzeigen:



In unserem Beispiel sind die Person, das Dokument und der binĂ€re „Körper“ der Datei „externe“ EntitĂ€ten, die unabhĂ€ngig von unserem Service existieren. Daher werden wir sie in Zukunft einfach als einige Links "irgendwo" von UUID wahrnehmen.
Zeichnen Sie die Diagramme so einfach wie möglich - die meisten, denen Sie sie zeigen, sind keine Experten fĂŒr das Lesen von UML / IDEF. Aber - seien Sie sicher, zu zeichnen.

Schritt 3: Skizzieren Sie die Tabellenstruktur


Über Tabellen- und Feldnamen
Die „russischen“ Namen von Feldern und Tabellen können unterschiedlich behandelt werden, dies ist jedoch Geschmackssache. Da wir in „Tensor“ keine auslĂ€ndischen Entwickler haben und PostgreSQL es uns erlaubt, Namen auch mit Hieroglyphen zu vergeben, wenn sie in AnfĂŒhrungszeichen gesetzt sind , bevorzugen wir es, Objekte eindeutig und klar zu benennen, damit es nicht zu MissverstĂ€ndnissen kommt.

Da viele Leute Nachrichten auf einmal schreiben, einige von ihnen dies offline tun können, besteht die einfachste Möglichkeit darin, UUIDs nicht nur fĂŒr externe EntitĂ€ten, sondern fĂŒr alle Objekte innerhalb unseres Dienstes als Bezeichner zu verwenden . DarĂŒber hinaus können sie auch auf der Client-Seite generiert werden - dies hilft uns, das Senden von Nachrichten mit kurzfristiger UnzugĂ€nglichkeit der Datenbank zu unterstĂŒtzen, und die Wahrscheinlichkeit einer Kollision ist Ă€ußerst gering.

Die grobe Struktur der Tabellen in unserer Datenbank sieht folgendermaßen aus:
Tabellen: RU
CREATE TABLE ""( "" uuid PRIMARY KEY , "" uuid , "" text ); CREATE TABLE ""( "" uuid PRIMARY KEY , "" uuid , "" uuid , "" timestamp , "" text ); CREATE TABLE ""( "" uuid , "" uuid , PRIMARY KEY("", "") ); CREATE TABLE ""( "" uuid PRIMARY KEY , "" uuid , "BLOB" uuid , "" text ); 

Tabellen: EN
 CREATE TABLE theme( theme uuid PRIMARY KEY , document uuid , title text ); CREATE TABLE message( message uuid PRIMARY KEY , theme uuid , author uuid , dt timestamp , body text ); CREATE TABLE message_addressee( message uuid , person uuid , PRIMARY KEY(message, person) ); CREATE TABLE message_file( file uuid PRIMARY KEY , message uuid , content uuid , filename text ); 

Die einfachste Möglichkeit, das Format zu beschreiben, besteht darin, das Diagramm der VerknĂŒpfungen aus Tabellen, die sich auf niemanden selbst beziehen , aufzulösen.

Schritt 4: Herausfinden nicht offensichtlicher Anforderungen


Das war's, wir haben eine Basis entworfen, in die man irgendwie schreiben und lesen kann.

Stellen wir uns an die Stelle des Nutzers unseres Dienstes - was wollen wir damit machen?

  • Aktuelle BeitrĂ€ge
    Dies ist ein Register mit "meinen" Nachrichten, chronologisch sortiert nach verschiedenen Merkmalen. Wo ich einer der EmpfÀnger bin, wo ich der Autor bin, wo sie mir geschrieben haben, aber ich habe nicht geantwortet, wo sie mir nicht geantwortet haben ...
  • Korrespondenten
    Wer ist an diesem langen, langen Chat beteiligt?

Unsere Struktur ermöglicht es uns, beide Probleme "allgemein", aber schnell zu lösen - nein. Das Problem besteht darin, dass fĂŒr die Sortierung im Rahmen der ersten Aufgabe kein fĂŒr jeden Teilnehmer geeigneter Index erstellt werden kann (und Sie alle DatensĂ€tze abrufen mĂŒssen). Zur Lösung des zweiten Problems mĂŒssen Sie alle Nachrichten zum Thema abrufen .
Unerwartete Benutzeraufgaben können die ProduktivitÀt beeintrÀchtigen.

Schritt 5: Angemessene Denormalisierung


Beide Probleme helfen, zusĂ€tzliche Tabellen zu lösen, in denen wir einen Teil der Daten duplizieren, die erforderlich sind, um Indizes zu bilden, die fĂŒr unsere Probleme geeignet sind.


Tabellen: RU
 CREATE TABLE ""( "" uuid , "" smallint , "" timestamp , "" uuid , PRIMARY KEY("", "", "") ); CREATE INDEX ON ""("", "", "" DESC); CREATE TABLE ""( "" uuid , "" uuid , PRIMARY KEY("", "") ); 

Tabellen: EN
 CREATE TABLE message_registry( owner uuid , registry smallint , dt timestamp , message uuid , PRIMARY KEY(owner, registry, message) ); CREATE INDEX ON message_registry(owner, registry, dt DESC); CREATE TABLE theme_participant( theme uuid , person uuid , PRIMARY KEY(theme, person) ); 

Hier haben wir zwei typische AnsÀtze angewendet, um Hilfstabellen zu erstellen:

  • MultiplikationsdatensĂ€tze
    Wir bilden mehrere QuelldatensĂ€tze gleichzeitig aus einem Quelldatensatz der Nachricht in unterschiedlichen Registertypen fĂŒr unterschiedliche EigentĂŒmer - sowohl fĂŒr den Absender als auch fĂŒr den EmpfĂ€nger. Aber jetzt liegt jede der Registrierungen im Index - weil wir im typischen Fall nur die erste Seite sehen wollen.
  • Record Uniqueization
    Jedes Mal, wenn Sie eine Nachricht innerhalb eines bestimmten Themas senden, genĂŒgt es zu ĂŒberprĂŒfen, ob ein solcher Eintrag bereits vorhanden ist. Wenn nicht, fĂŒgen Sie es unserem "Wörterbuch" hinzu.

Im nÀchsten Teil des Artikels werden wir die Implementierung von Sectioning in der Struktur unserer Datenbank diskutieren.

Source: https://habr.com/ru/post/de483176/


All Articles