BD-ul messenger-ului (partea 1): proiectarea structurii bazei de date

Cum putem transforma cerințele de afaceri în structuri de date specifice, folosind ca exemplu proiectarea unei baze de date de la zero pentru un messenger.

BD-ul messenger-ului (partea 1): proiectarea structurii bazei de date
Baza noastră nu va fi la fel de extinsă și distribuită, ca cea de la Vkontakte, sau Badoo, ci «de dragul existenței», dar va fi bine - funcțională, rapidă și se va încadra pe un singur server. PostgreSQL - astfel încât să putem desfășura o instanță separată a serviciului undeva, de exemplu.

Prin urmare, nu vom aborda problemele de sharding, replicare și sisteme geo-distribuite, ci ne vom concentra pe soluțiile schemei din interiorul Bazei de date.

Pasul 1: Puțin context de afaceri

Își vom proiecta schimbul de mesaje nu în mod abstract, ci integrat în contextul rețelei sociale corporative.. Adică, oamenii nu «se scriu doar», ci comunică între ei în contextul rezolvării anumitor sarcini de afaceri.

Și ce tipuri de sarcini are o afacere?.. Să ne uităm la exemplul lui Vasili — șeful departamentului de dezvoltare.

  • «Nikolai, pentru această sarcină trebuie un patch chiar astăzi!»
    Deci, discuțiile pot avea loc în contextul unui document..
  • «Kola, să jucăm seara Dota?»
    Adică, chiar și între o pereche de interlocutori, comunicarea poate avea loc simultan pe subiecte diferite..
  • «Petru, Nikolai, uitați-vă în atașament la prețul pentru noul server.»
    Așadar, un mesaj poate avea mai multe destinatari.. În același timp, mesajul poate conține fișiere atașate..
  • «Semen, și tu uită-te și tu.»
    Și trebuie să existe posibilitatea de a invita un nou participant în conversația existentă. Să ne concentrăm pentru moment pe această listă de necesități «evidente»..

Fără înțelegerea specificului aplicației sarcinii și a limitărilor pe care le impune, este practic imposibil să proiectezi

o schemă eficientă a bazei de date pentru rezolvarea acesteia. Pasul 2: Schema logică minimă

Schema arată până acum foarte asemănător cu corespondența prin email - instrumentul tradițional de afaceri. Așa este, «algoritmic», multe sarcini de afaceri sunt asemănătoare între ele, deci și instrumentele pentru rezolvarea lor vor fi structural similare.

Haideți să fixăm schema logică a relațiilor entităților obținute. Pentru a simplifica înțelegerea modelului nostru, vom folosi cea mai primitivă variantă de reprezentare

a modelului ER, fără complicații UML sau note IDEF: fără complicații UML sau note IDEF:

BD-ul messenger-ului (partea 1): proiectarea structurii bazei de date

În exemplul nostru, persona, documentul și corpul binar al fișierului sunt entități „externe” care există independent de serviciul nostru. Prin urmare, le vom percepe în continuare ca referințe „către ceva” prin UUID.

Desenați diagrame cât mai simplu — majoritatea celor cărora le veți arăta aceste diagrame nu sunt experți în citirea UML/IDEF. Dar — trebuie să desenați.

Pasul 3: Schițăm structura tabelelor

Despre numele tabelelor și câmpurilorLa numele „rusesti” ale câmpurilor și tabelelor se poate privi diferit, dar asta este o chestiune de gust. Având în vedere că nu avem dezvoltatori străini în „Tensor” iar PostgreSQL ne permite să folosim nume chiar și cu hieroglife, dacă ele sunt între ghilimele, preferăm să numim obiectele într-un mod clar, astfel încât să nu apară ambiguități.
Deoarece mesajele sunt scrise de mai multe persoane simultan, o parte dintre ele pot face acest lucru în mod offline, cea mai simplă opțiune ar fi să folosim UUID ca identificatori nu doar pentru entitățile externe, ci și pentru toate obiectele din cadrul serviciului nostru. De fapt, le putem genera chiar și pe partea clientului — aceasta ne va ajuta să susținem trimiterea mesajelor în caz de nefuncționare temporară a bazei de date, iar probabilitatea coliziunii este extrem de mică.

Structura preliminară a tabelelor din baza noastră va arăta astfel:
Tabele: RU

CREATE TABLE "Tema"(
  "Tema"
    uuid
      PRIMARY KEY
, "Document"
    uuid
, "Titlu"
    text
);

CREATE TABLE "Mesaj"(
  "Mesaj"
    uuid
      PRIMARY KEY
, "Tema"
    uuid
, "Autor"
    uuid
, "DataOra"
    timestamp
, "Text"
    text
);

CREATE TABLE "Adresat"(
  "Mesaj"
    uuid
, "Persona"
    uuid
, PRIMARY KEY("Mesaj", "Persona")
);

CREATE TABLE "Fișier"(
  "Fișier"
    uuid
      PRIMARY KEY
, "Mesaj"
    uuid
, "BLOB"
    uuid
, "Nume"
    text
);

Tabele: 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
);

Cea mai simplă abordare în descrierea formatului este să începem „dezvoltarea” rețelei de relații de la tabele care nu se referă la nimeni.

Pasul 4: Identificăm nevoile neștiute

Totul, am proiectat o bază în care putem scrie excelent și într-un fel să citim.

Să ne punem în locul utilizatorului serviciului nostru - ce am dori să facem cu ajutorul lui?

  • Cele mai recente mesaje
    Aceasta un registru "al mesajelor mele" ordonat cronologic. Unde sunt unul dintre destinatari, unde sunt autor, unde mi s-a scris și nu am răspuns, unde nu mi s-a răspuns, …
  • Participanții la corespondență
    Cine participă de fapt la această discuție foarte lungă?

Structura noastră permite să rezolvăm ambele aceste sarcini "în general", însă rapid - nu. Problema este că pentru a sorta în cadrul primei sarcini nu este posibil să se creeze un index, potrivit pentru fiecare dintre participanți (va trebui să extragem toate înregistrările), iar pentru a rezolva a doua sarcină este necesar să extragem toate mesajele pe temă.

Sarcinile utilizatorilor neprevăzute pot pune un accent serios pe performanță.

Pasul 5: Denormalizare rațională

Ambele probleme ale noastre pot fi rezolvate prin tabele suplimentare, în care vom duplicat o parte din datele, necesare pentru a forma indici adecvați pentru sarcinile noastre.
BD-ul messenger-ului (partea 1): proiectarea structurii bazei de date

Tabele: RU

CREATE TABLE "RegistryMessages"(
  "Owner"
    uuid
, "RegistryType"
    smallint
, "DateTime"
    timestamp
, "Message"
    uuid
, PRIMARY KEY("Owner", "RegistryType", "Message")
);
CREATE INDEX ON "RegistryMessages"("Owner", "RegistryType", "DateTime" DESC);

CREATE TABLE "ThemeParticipant"(
  "Theme"
    uuid
, "Person"
    uuid
, PRIMARY KEY("Theme", "Person")
);

Tabele: 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)
);

Aici am aplicat două abordări tipice utilizate la crearea tabelelor auxiliare:

  • Înmulțirea înregistrărilor
    Formăm dintr-o înregistrare inițială a unui mesaj mai multe înregistrări-urmă în diferite tipuri de registre pentru diferiți proprietari - atât pentru expeditor, cât și pentru destinatar. Dar acum fiecare registru se potrivește pe index - căci în cazul tipic dorim să vedem doar prima pagină.
  • Unicizarea înregistrărilor
    La fiecare trimitere a unui mesaj într-o temă specifică, este suficient să verificăm dacă o astfel de înregistrare există deja. Dacă nu, o adăugăm în „glosarul” nostru.

În partea următoare a articolului ne vom ocupa de implementarea partajării în structura bazei noastre.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster