Wie man GeschĂ€ftsanforderungen in spezifische Datenstrukturen umwandelt am Beispiel der Planung einer Datenbank von Grund auf fĂŒr einen Messenger.
- Teil 1: das GerĂŒst der Datenbank entwerfen

Unsere Datenbank wird nicht so groĂ und verteilt sein wie die von oder , sondern eher bescheiden, aber dennoch gut â funktional, schnell und auf einem Server Platz finden. PostgreSQL â damit wir einen separaten Instanz des Dienstes irgendwo anders bereitstellen können, zum Beispiel.
Deshalb werden wir keine Fragen zu Sharding, Replikation und geo-distribuierten Systemen behandeln, sondern uns auf die strukturellen Lösungen innerhalb der Datenbank konzentrieren.
Schritt 1: Ein wenig geschÀftsspezifische Informationen
Wir werden unseren Nachrichtenaustausch nicht abstrakt entwerfen, sondern in die Umgebung integrieren. Das heiĂt, die Menschen kommunizieren nicht einfach, sondern interagieren im Kontext der Lösung spezifischer GeschĂ€ftsprobleme.
Welche Aufgaben hat ein Unternehmen?... Schauen wir uns das am Beispiel von Vasily, dem Leiter der Entwicklungsabteilung, an.
- "Nikolai, der Patch fĂŒr diese Aufgabe wird bereits heute benötigt!"
Das bedeutet, dass die Kommunikation im Kontext von etwas stattfinden kann. des Dokuments. - "Koya, lass uns heute Abend Dota spielen?"
Das bedeutet, dass sogar bei einem Paar von GesprĂ€chspartnern gleichzeitig ĂŒber verschiedene Themen kommuniziert werden kann.. - âPeter, Nikolai, schaut euch im Anhang die Preisliste fĂŒr den neuen Server an.â
So kann eine Nachricht mehrere EmpfĂ€nger haben.. Dabei kann die Nachricht angehĂ€ngte Dateien enthalten.. - âSemen, du solltest auch einen Blick darauf werfen.â
Und es sollte möglich sein, einen neuen Teilnehmer in die bereits bestehende Korrespondenz einzuladen..
Lassen Sie uns vorerst bei dieser Liste der âoffensichtlichenâ BedĂŒrfnisse bleiben.
Ohne das VerstĂ€ndnis der spezifischen Anforderungen und der ihnen auferlegten EinschrĂ€nkungen ist es praktisch unmöglich, eine effektive Datenbankschema fĂŒr deren Lösung zu entwerfen.
Schritt 2: Minimales logisches Schema
VorlĂ€ufig Ă€hnelt alles sehr der E-Mail-Korrespondenz â einem traditionellen GeschĂ€ftsfĂŒhrungstool. Ja, âalgorithmischâ Ă€hneln sich viele GeschĂ€ftsaufgaben, daher werden auch die Werkzeuge zu ihrer Lösung strukturell Ă€hnlich sein.
Lassen Sie uns das bereits erhaltene logische Schema der EntitÀtenbeziehungen festhalten. Zur Vereinfachung des VerstÀndnisses unserer Modell nutzen wir die einfachste Form der Darstellung ohne komplizierte UML- oder IDEF-Notation.

In unserem Beispiel sind die Persona, das Dokument und das binĂ€re âKörperâ der Datei âexterneâ EntitĂ€ten, die unabhĂ€ngig von unserem Dienst existieren. Daher betrachten wir sie kĂŒnftig einfach als Links âirgendwoâ ĂŒber UUID.
Zeichnen Sie Schemen so einfach wie möglich â Die meisten derjenigen, die Sie sie zeigen werden, sind keine Experten im Lesen von UML/IDEF. Aber zeichnen Sie unbedingt.
Schritt 3: Skizzieren Sie die Struktur der Tabellen
Ăber die Namen von Tabellen und FeldernZu 'russischen' Bezeichnungen fĂŒr Felder und Tabellen kann man unterschiedlich stehen, aber das ist Geschmackssache. Da keine auslĂ€ndischen Entwickler haben und PostgreSQL uns erlaubt, auch mit Hieroglyphen zu benennen, wenn sie in AnfĂŒhrungszeichen stehen, bevorzugen wir es, Objekte eindeutig verstĂ€ndlich zu benennen, um MissverstĂ€ndnisse zu vermeiden.
Da viele Menschen gleichzeitig Nachrichten schreiben, können einige von ihnen dies im Offline-Modus, ist die einfachste Option â UUIDs als Identifikatoren zu verwenden nicht nur fĂŒr externe EntitĂ€ten, sondern auch fĂŒr alle Objekte innerhalb unseres Dienstes. Zudem können sie sogar auf der Client-Seite generiert werden â das hilft uns, den Versand von Nachrichten bei kurzfristiger NichtverfĂŒgbarkeit der DB aufrechtzuerhalten, und die Wahrscheinlichkeit einer Kollision ist Ă€uĂerst niedrig.
Die Rohstruktur der Tabellen in unserer Datenbank wird folgendermaĂen aussehen:
Tabellen : RU
ERSTELLE TABELLE "Thema"(
"Thema"
uuid
PRIMARY KEY
, "Dokument"
uuid
, "Titel"
text
);
ERSTELLE TABELLE "Nachricht"(
"Nachricht"
uuid
PRIMARY KEY
, "Thema"
uuid
, "Autor"
uuid
, "DatumUhrzeit"
timestamp
, "Text"
text
);
ERSTELLE TABELLE "EmpfÀnger"(
"Nachricht"
uuid
, "Person"
uuid
, PRIMARY KEY("Nachricht", "Person")
);
ERSTELLE TABELLE "Datei"(
"Datei"
uuid
PRIMARY KEY
, "Nachricht"
uuid
, "BLOB"
uuid
, "Name"
text
);Tabellen : EN
ERSTELLE TABELLE thema(
thema
uuid
PRIMARY KEY
, dokument
uuid
, titel
text
);
ERSTELLE TABELLE nachricht(
nachricht
uuid
PRIMARY KEY
, thema
uuid
, autor
uuid
, dt
timestamp
, text
text
);
ERSTELLE TABELLE nachricht_empfÀnger(
nachricht
uuid
, person
uuid
, PRIMARY KEY(nachricht, person)
);
ERSTELLE TABELLE nachricht_datei(
datei
uuid
PRIMARY KEY
, nachricht
uuid
, inhalt
uuid
, dateiname
text
);Am einfachsten beginnt man bei der Beschreibung des Formats, indem man die Beziehungsgrafik "enthĂŒllt". von Tabellen, die nicht referenzieren sich selbst auf niemanden.
Schritt 4: Offensichtliche BedĂŒrfnisse klĂ€ren
So, wir haben eine Datenbank entworfen, in die man ausgezeichnet schreiben und irgendwie lesen kann.
Lassen Sie uns in die Lage des Nutzers unseres Services versetzen â was wĂŒrden wir mit dessen Hilfe tun wollen?
- Neueste Nachrichten
Das chronologisch sortiert nach verschiedenen Kriterien eine Ăbersicht meiner Nachrichten. Wo ich einer der Adressaten bin, wo ich der Autor bin, wo man mir geschrieben hat, aber ich nicht geantwortet habe, wo mir nicht geantwortet wurde, ⊠- Teilnehmer der Konversation
Wer nimmt eigentlich an diesem langen, langen Chat teil?
Unsere Struktur ermöglicht es, beide Aufgaben âinsgesamtâ zu lösen, aber schnell â nein. Das Problem ist, dass fĂŒr die Sortierung im Rahmen der ersten Aufgabe es unmöglich ist, einen Index zu erstellen, der fĂŒr jeden der Teilnehmer geeignet ist (und man muss alle Aufzeichnungen abrufen), und zur Lösung der zweiten Aufgabe ist es notwendig alle Nachrichten zum Thema zu extrahieren.
Unvorhergesehene Benutzeraufgaben können ein fettes Kreuz fĂŒr die Leistung setzen..
Schritt 5: Sinnvolle Denormalisierung
Beide unsere Probleme können durch zusĂ€tzliche Tabellen gelöst werden, in die wir einen Teil der Daten duplizieren, die erforderlich sind, um geeignete Indizes fĂŒr unsere Aufgaben zu erstellen.

Tabellen : RU
CREATE TABLE "Nachrichtenregister"(
"EigentĂŒmer"
uuid
, "RegistryTyp"
smallint
, "DatumUhrzeit"
timestamp
, "Nachricht"
uuid
, PRIMARY KEY("EigentĂŒmer", "RegistryTyp", "Nachricht")
);
CREATE INDEX ON "Nachrichtenregister"("EigentĂŒmer", "RegistryTyp", "DatumUhrzeit" DESC);
CREATE TABLE "ThemenTeilnehmer"(
"Thema"
uuid
, "Person"
uuid
, PRIMARY KEY("Thema", "Person")
);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, die beim Erstellen von Hilfstabellen verwendet werden:
- Multiplikation von DatensÀtzen
Wir erstellen aus einem ursprĂŒnglichen Nachrichtendatensatz mehrere FolgedatensĂ€tze in verschiedene Arten von Registern fĂŒr unterschiedliche EigentĂŒmer â sowohl fĂŒr den Absender als auch fĂŒr den EmpfĂ€nger. So wird jedes Register nun auf einen Index gelegt â denn im typischen Fall möchten wir nur die erste Seite sehen. - Eindeutigkeit der DatensĂ€tze
Bei jedem Versenden einer Nachricht innerhalb eines bestimmten Themas genĂŒgt es zu ĂŒberprĂŒfen, ob ein solcher Datensatz bereits existiert. Wenn nicht â fĂŒgen wir ihn in unser âWörterbuchâ ein.
Im nÀchsten Teil des Artikels wird es um in die Struktur unserer Datenbank.
Quelle: habr.com
