Hvordan man kan oversĂŠtte forretningskrav til konkrete datastrukturer ved at designe en database til en messenger "fra bunden".
- Del 1: design rammen pÄ databasen

Vores database vil ikke vĂŠre sĂ„ omfattende og distribueret, eller , men "bare for at have det", skal den vĂŠre god â funktionel, hurtig og kunne vĂŠre pĂ„ Ă©n server PostgreSQL â sĂ„ vi kan implementere en separat tjenesteinstans et sted, for eksempel.
Derfor vil vi ikke berÞre spÞrgsmÄl om sharding, replikering og geografisk distribuerede systemer, men fokusere pÄ skematiske lÞsninger inden for databasen.
Trin 1: Lidt forretningsspecifik viden
Vi vil designe vores beskedudveksling ikke abstrakt, men indbygget i miljĂžet . Det vil sige, at folk ikke "bare skriver til hinanden", men kommunikerer i konteksten af at lĂžse bestemte forretningsopgaver.
Hvilke opgaver har virksomhederne? Lad os se pÄ et eksempel med Vasily - lederen af udviklingsafdelingen.
- "Nikolaj, vi har brug for en patch til denne opgave i dag!"
Det betyder, at kommunikationen kan finde sted i konteksten af et dokument. - "Kola, skal vi spille Dota i aften?"
Det vil sige, at selv for et par samtalepartnere kan kommunikationen finde sted om forskellige emner. - "Petr, Nikolaj, kig i det vedhÊftede dokument for prisen pÄ den nye server."
SÄ et enkelt besked kan have flere modtagere.Desuden kan en besked indeholde vedhÊftede filer. - "Semen, du skal ogsÄ tage et kig."
Og der skal vÊre mulighed for at invitere en ny deltager ind i en eksisterende samtale Lad os holde os til denne liste af "Äbenlyse" behov..
Uden forstÄelse af de applikationsspecifikke opgaver og deres begrÊnsninger er det praktisk talt umuligt at designe
en effektiv database schema til at lĂžse dem. Trin 2: Minimal logisk skema
Skematisk set ligner alt stadig meget en email-korrespondance â et traditionelt vĂŠrktĂžj til at drive forretning. SĂ„ ja, "algoritmisk" minder mange forretningsopgaver om hinanden, derfor vil vĂŠrktĂžjerne til at lĂžse dem ogsĂ„ have strukturel lighed.
Lad os fastholde den logiske skema for enhedsrelationerne, vi allerede har fÄet. For at forenkle forstÄelsen af vores model vil vi bruge den mest primitive form for visning
af ER-modellen. uden komplicerede UML eller IDEF-notationer:

I vores eksempel er person, dokument og den binĂŠre "krop" af filen "eksterne" enheder, der eksisterer uafhĂŠngigt af vores service. Derfor vil vi blot opfatte dem som nogle links "et eller andet sted" via UUID.
Tegn skemaer sĂ„ enkelt som muligt â de fleste af dem, du viser dem til, er ikke eksperter i at lĂŠse UML/IDEF. Men â sĂžrg for at tegne.
Trin 3: Skitser strukturen af tabeller
Om navne pÄ tabeller og felterMan kan have forskellige holdninger til "russiske" navne pÄ felter og tabeller, men det er en smagssag. Da ikke har udenlandske udviklere, og PostgreSQL tillader os at give navne selv i hieroglyffer, sÄ lÊnge de er indkapslet i anfÞrselstegn, sÄ foretrÊkker vi at navngive objekter klart og tydeligt for at undgÄ misforstÄelser.
Da mange mennesker skriver beskeder til os pĂ„ Ă©n gang, kan nogle endda gĂžre det i offline-tilstand, sĂ„ den enkleste lĂžsning er at bruge UUID som identifikatorer ikke kun for eksterne enheder, men ogsĂ„ for alle objekter inden for vores service. Desuden kan de genereres selv pĂ„ klientsiden â det hjĂŠlper os med at stĂžtte afsendelse af beskeder ved kortvarig utilgĂŠngelighed af databasen, og risikoen for kollision er ekstremt lille.
Den udkastede struktur af tabellerne i vores database vil have fĂžlgende udseende:
Tabeller : RU
CREATE TABLE "Emne"(
"Emne"
uuid
PRIMARY KEY
, "Dokument"
uuid
, "Titel"
text
);
CREATE TABLE "Besked"(
"Besked"
uuid
PRIMARY KEY
, "Emne"
uuid
, "Forfatter"
uuid
, "DatoTid"
timestamp
, "Tekst"
text
);
CREATE TABLE "Modtager"(
"Besked"
uuid
, "Person"
uuid
, PRIMARY KEY("Besked", "Person")
);
CREATE TABLE "Fil"(
"Fil"
uuid
PRIMARY KEY
, "Besked"
uuid
, "BLOB"
uuid
, "Navn"
text
);Tabeller : 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
);Det simpleste, nÄr man beskriver formatet, er at begynde at "folde" forbindelsesgrafen fra tabeller, der ikke henviser til nogen.
Trin 4: Afklare skjulte behov
Det er det, vi har designet en database, hvor man kan skrive og pÄ en eller anden mÄde lÊse.
Lad os sĂŠtte os i brugerens sted â hvad vi Ăžnsker at gĂžre med vores service?
- Seneste beskeder
Dette kronologisk sorteret register over 'mine' beskeder. Hvor jeg er en af modtagerne, hvor jeg er forfatter, hvor jeg er blevet skrevet til, men ikke svarede, hvor jeg ikke fik svar, ⊠- Deltagere i samtalen
Hvem deltager egentlig i denne lange chat?
Vores struktur gĂžr det muligt at lĂžse begge disse opgaver, men hurtigt â nej. Problemet er, at det er umuligt at oprette et indeks , der passer til hver deltager (og vi mĂ„ hente alle registreringer), mens det for at lĂžse den anden opgave er nĂždvendigtat hente alle beskeder om emnet. Uforudsete brugeropgaver kan sĂŠtte en fed
streg over ydeevnen Trin 5: Fornuftig denormalisering.
Begge vores problemer kan lĂžses med ekstra tabeller, hvor vi vil
duplikere en del af de data , der er nĂždvendige for at danne passende indekser til vores opgaver.CREATE TABLE "MessageRegistry"( "Owner" uuid , "RegistryType" smallint , "Datetime" timestamp , "Message" uuid , PRIMARY KEY("Owner", "RegistryType", "Message") ); CREATE INDEX ON "MessageRegistry"("Owner", "RegistryType", "Datetime" DESC);CREATE TABLE "ThemeParticipant"( "Theme" uuid , "Person" uuid , PRIMARY KEY("Theme", "Person") );

Tabeller : RU
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)
);Tabeller : EN
Her har vi anvendt to typiske metoder, der bruges ved oprettelse af hjĂŠlpe-tabeller:Multiplicering af optegnelser
- Vi danner for hver enkelt indledende besked straks flere fĂžlgeoptegnelser i forskellige typer registrer for forskellige ejere â bĂ„de for afsenderen og modtageren. Men nu passer hver registrering ind pĂ„ indekset â for i typisk tilfĂŠlde Ăžnsker vi kun at se fĂžrste side.
Unikalisering af optegnelser - Ved hver afsendelse af en besked inden for et bestemt emne er det nok at kontrollere, om en sĂ„dan optegnelse allerede findes. Hvis ikke â tilfĂžjer vi den til vores 'ordbog'.
I den nÊste del af artiklen vil der vÊre fokus pÄ
implementering af partitionering Arkitektur til opbevaring og levering af billeder i Badoo
Kilde: habr.com
