Sõnumite andmebaas (osa 1): projekteerime andmebaasi struktuuri

Kuidas saab äritegevuse nõuded konkreetseteks andmestruktuurdeks tõlkida, kasutades näiteks "nullist" saadud andmebaasi projekteerimist sõnumivahetuseks.

Sõnumite andmebaas (osa 1): projekteerime andmebaasi struktuuri
Meie andmebaas ei saa olema nii ulatuslik ja jaotatud, nagu VKontakte või Badoo, vaid pigem "et oleks", aga siiski hästi — funktsionaalne, kiire ja mahtuks ühele serverile. PostgreSQL — et saaksime käivitada eraldi teenuse eksemplari kuskil kõrval, näiteks.

Seega ei käsitle me shardimise, replikatsiooni ja geograafiliste süsteemide küsimusi, vaid keskendume skeemilistele lahendustele andmebaasi sees.

Samm 1: Veidi ärispetsiifikat.

Meie sõnumivahetust projekteerime mitte abstraktselt, vaid integreerime ettevõtte sotsiaalvõrku. See tähendab, et inimesed ei "lihtsalt suhtle", vaid suhtlevad omavahel teatud äriülesannete täitmise kontekstis.. Millised äriülesanded on? Vaatame näiteks Vassili näitel — arendusosakonna juhti.

"Nikolai, selle ülesande jaoks on täna juba vajalik patch!"

  • See tähendab, et suhtlemine võib toimuma näiteks mingis kontekstis
    "Kola, lähme täna õhtul Dota mängima?" dokument.
  • See tähendab, et isegi ühe paarikese vestluses võib suhtlemine samal ajal toimuda.
    То есть даже у одной пары собеседников общение одновременно может вестись erinevate teemadega.
  • „Petr, Nikolai, vaadake manuses uusi serveri hindu.“
    Ühel sõnumil võib olla mitu saajat. Samuti võib sõnum sisaldada manustatud faile.
  • „Semen, ka sina vaata seda.“
    Ja peab olema võimalus juba olemasolevasse vestlusse kaasa kutsuda uus osaleja.

Peatume praegu sellel nimekirjal „ilmselgetest“ vajadustest.

Ilma rakenduslikke eripärasid ülesande ja selle kehtestatud piirangute mõistmata on praktiliselt võimatu projekteerida tõhusat andmebaasi skeemi selle lahendamiseks.

2. samm: minimaalne loogiline skeem

Skeemiliselt tundub kõik väga sarnane e-kirjadevahetusele — traditsioonilisele ärivahendile. Jah, „algtude“ paljud äriülesanded näevad välja sarnased, seega on ka nende lahendamiseks vajalikud tööriistad struktuurselt sarnased.

Kinnitatame juba saadud loogilise suhete skeemi. Arusaamise lihtsustamiseks meie mudelisse kasutame kõige primitiivsemaid kuvamisviise ER-mudeleid ilma UML või IDEF-märkuste keerukusteta:

Sõnumite andmebaas (osa 1): projekteerime andmebaasi struktuuri

Meie näites on tegelane, dokument ja faili binaarne "keha" "välistest" üksustest, mis eksisteerivad iseseisvalt ilma meie teenuseta. Seetõttu tajume neid edaspidi kui mõningaid linke "kuidas iganes", kasutades UUID-d.

Joonistage skeeme nii lihtsalt kui võimalik — enamiku nende jaoks, kellele te neid näitate, ei ole UML/IDEF lugemise eksperdid. Kuid — kindlasti joonistage.

Samm 3: Joonistame tabelite struktuuri

Tabelite ja väljade nimedestK 'vene' tabeli ja väljade nimede suhtes võib suhtuda erinevalt, kuid see on maits küsimus. Kuna meil 'Tensoris' ei ole välismaalaste arendajaid, ja PostgreSQL võimaldab meil nime anda isegi hieroglüüfidega, kui need on jutumärkides, siis eelistame nimetada objekte üheselt mõistetavalt, et vältida tõlgenduste erinevusi.
Kuna sõnumeid kirjutab meil mitu inimest korraga, võivad mõned neist seda teha offline-režiimis, siis kõige lihtsam variant on kasutada UUID-d identifikaatoritena mitte ainult välistes üksustes, vaid ka kõigi objektide jaoks meie teenuses. Täiendavaks plussiks on see, et neid saab genereerida isegi kliendi poolel — see aitab meil sõnumite saatmist toetada lühiajalise andmebaasi kättesaamatuse korral, ja kokkupõrke tõenäosus on äärmiselt madal.

Meie andmebaasi tööversioon tabelite struktuur näeb välja järgmine:
Tabelid: RU

LOOJA TABEL "Teema"(
  "Teema"
    uuid
      PEAMISED VÕTME
, "Dokument"
    uuid
, "Pealkiri"
    tekst
);

LOOJA TABEL "Sõnum"(
  "Sõnum"
    uuid
      PEAMISED VÕTME
, "Teema"
    uuid
, "Autor"
    uuid
, "KuupäevAeg"
    timestamp
, "Tekst"
    tekst
);

LOOJA TABEL "Aadressaat"(
  "Sõnum"
    uuid
, "Isik"
    uuid
, PEAMISED VÕTME("Sõnum", "Isik")
);

LOOJA TABEL "Fail"(
  "Fail"
    uuid
      PEAMISED VÕTME
, "Sõnum"
    uuid
, "BLOB"
    uuid
, "Nimi"
    tekst
);

Tabelid : EN

LOOJA TABEL teema(
  teema
    uuid
      PEAMISED VÕTME
, dokument
    uuid
, pealkiri
    tekst
);

LOOJA TABEL sõnum(
  sõnum
    uuid
      PEAMISED VÕTME
, teema
    uuid
, autor
    uuid
, dt
    timestamp
, keha
    tekst
);

LOOJA TABEL sõnum_aadressaat(
  sõnum
    uuid
, isik
    uuid
, PEAMISED VÕTME(sõnum, isik)
);

LOOJA TABEL sõnum_fail(
  fail
    uuid
      PEAMISED VÕTME
, sõnum
    uuid
, sisu
    uuid
, failinimi
    tekst
);

Lihtsaim viis formaadi kirjeldamiseks on alustada suhete graafist tabelitest, mis ei viita mingile teisele.

Samm 4: Selgitame välja mitte ilmsed vajadused

Oleme projekteerinud andmebaasi, kuhu on suurepärane kirjutada ja kuidagi lugeda.

Pange end meie teenuse kasutaja olukorda — mida me sooviksime selle abil teha?

  • Viimased sõnumid
    See kronoloogiliselt järjestatud minu sõnumite register eri kriteeriumide järgi. Kus ma olen üks adressaatidest, kus ma olen autor, kus kirjutati mulle, aga ma ei vastanud, kus mulle ei vastatud, …
  • Vestluse osalejad
    Kes on üldse selles pikale veninud vestluses osalised?

Meie struktuur võimaldab lahendada mõlemat ülesannet „üldiselt“, kuid kiiresti - ei. Probleem on selles, et esimese ülesande raames sortimise jaoks pole võimalik luua indeksi, mis sobib igale osalejale (ja tuleb välja võtta kõik salvestised), ning teise ülesande lahendamiseks on vajalik välja võtta kõik sõnumid teema kohta.

Ette nähtud kasutajaprobleemid võivad tõsiselt kahjustada tulemusi.

Samm 5: Mõistlik denormaalimine

Mõlemad meie probleemid aitavad lahendada täiendavad tabelid, kuhu me kavatseme duplitseerida osa andmeid, mis on vajalik nendele ülesannetele vastavate indeksite moodustamiseks.
Sõnumite andmebaas (osa 1): projekteerime andmebaasi struktuuri

Tabelid: RU

Loo tabel "SõnumiteRegister"(
  "Omanik"
    uuid
, "RegistriTüüp"
    smallint
, "KuupäevAeg"
    timestamp
, "Sõnum"
    uuid
, PRIMARY KEY("Omanik", "RegistriTüüp", "Sõnum")
);
Loo indeks "SõnumiteRegister"("Omanik", "RegistriTüüp", "KuupäevAeg" DESC);

Loo tabel "TeemaOsaleja"(
  "Teema"
    uuid
, "Isik"
    uuid
, PRIMARY KEY("Teema", "Isik")
);

Tabelid : EN

Loo tabel message_registry(
  owner
    uuid
, registry
    smallint
, dt
    timestamp
, message
    uuid
, PRIMARY KEY(owner, registry, message)
);
Loo indeks message_registry(owner, registry, dt DESC);

Loo tabel theme_participant(
  theme
    uuid
, person
    uuid
, PRIMARY KEY(theme, person)
);

Siin rakendasime kahte tüüpilist lähenemist, mida kasutatakse abitaabelite loomisel:

  • Kirjete paljundamine
    Loome ühe algse sõnumi põhjal mitu järgmise kirje varianti eri registrites erinevatele omanikele — nii saatjale kui ka saajale. Nüüd sobitub iga register indeksisse, sest tüüpiliselt tahame näha ainult esimest lehte.
  • Kirjete unikaalsus
    Iga sõnumi saatmise korral antud teemas piisab, et kontrollida, kas selline kirje juba eksisteerib. Kui ei, siis lisame selle meie "sõnaraamatusse".

Järgmises artikli osas räägime sektsioonide rakendamine meie andmebaasi struktuuri.

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster