Databáza Messenger (časť 2): rozdelenie „za účelom zisku“

Úspešne sme navrhli štruktúru našej databázy PostgreSQL na ukladanie korešpondencie, prešiel rok, používatelia ju aktívne napĺňajú a teraz obsahuje milióny záznamov, a... niečo sa začalo spomaľovať.

Databáza Messenger (časť 2): rozdelenie „za účelom zisku“
Faktom je, že S rastúcou veľkosťou tabuľky rastie aj „hĺbka“ indexov. - aj keď logaritmicky. Ale časom to núti server vykonávať rovnaké úlohy čítania/zápisu spracovať mnohonásobne viac strán údajovnež na začiatku.

Tu prichádza na rad záchrana delenie.

Dovoľte mi poznamenať, že nehovoríme o shardingu, teda o distribúcii údajov medzi rôznymi databázami alebo servermi. Pretože aj delenie dát do niektorí sa časom nezbavíte problému „napučiavania“ indexov. Je jasné, že ak si môžete dovoliť každý deň sprevádzkovať nový server, vaše problémy už nebudú vôbec ležať v rovine konkrétnej databázy.

Nebudeme uvažovať o konkrétnych skriptoch na implementáciu rozdelenia „v hardvéri“, ale o samotnom prístupe - čo a ako by sa malo „rozrezať na plátky“ a k čomu takáto túžba vedie.

pojem

Ešte raz si definujme náš cieľ: chceme sa uistiť, že dnes, zajtra a o rok zostane množstvo dát prečítaných PostgreSQL počas akejkoľvek operácie čítania/zápisu približne rovnaké.

Pre akékoľvek chronologicky zhromaždené údaje (správy, dokumenty, protokoly, archívy, ...) je prirodzenou voľbou ako rozdeľovací kľúč dátum/čas udalosti. V našom prípade taká udalosť je moment odoslania správy.

Všimnite si, že používatelia takmer vždy pracovať len s tými „najnovšími“. takéto údaje - čítajú najnovšie správy, analyzujú najnovšie záznamy,... Nie, samozrejme, môžu sa posúvať ďalej v čase, ale robia to veľmi zriedka.

Z týchto obmedzení je jasné, že optimálne riešenie správy by bolo „denné“ časti - veď náš používateľ si takmer vždy prečíta, čo mu prišlo „dnes“ alebo „včera“.

Ak cez deň píšeme a čítame takmer len v jednom úseku, tak aj toto nám dáva efektívnejšie využitie pamäte a disku - pretože všetky indexy sekcií sa ľahko zmestia do pamäte RAM, na rozdiel od „veľkých a tučných“ v tabuľke.

krok za krokom

Vo všeobecnosti všetko uvedené vyššie znie ako jeden nepretržitý zisk. A je to dosiahnuteľné, ale o to sa budeme musieť veľmi snažiť - pretože rozhodnutie rozdeliť jednu z entít vedie k potrebe „vidieť“ súvisiace.

Správa, jej vlastnosti a projekcie

Keďže sme sa rozhodli skrátiť správy podľa dátumov, má zmysel rozdeliť aj entity-vlastnosti, ktoré od nich závisia (priložené súbory, zoznam príjemcov) a aj podľa dátumu správy.

Keďže jednou z našich typických úloh je presné prezeranie registrov správ (neprečítané, prichádzajúce, všetky), je tiež logické ich „vtiahnuť“ do rozdelenia podľa dátumov správ.

Databáza Messenger (časť 2): rozdelenie „za účelom zisku“

Rozdeľovací kľúč (dátum správy) pridáme do všetkých tabuliek: príjemcovia, súbor, registre. Nemusíte ho pridávať do samotnej správy, ale použite existujúci DateTime.

nite

Keďže existuje iba jedna téma pre niekoľko správ, neexistuje spôsob, ako ju „strihnúť“ v rovnakom modeli, musíte sa spoľahnúť na niečo iné. V našom prípade je to ideálne dátum prvej správy v korešpondencii — teda moment vzniku, vlastne témy.

Databáza Messenger (časť 2): rozdelenie „za účelom zisku“

Pridajte rozdeľovací kľúč (dátum témy) do všetkých tabuliek: téma, účastník.

Teraz však máme dva problémy naraz:

  • V ktorej sekcii mám hľadať správy k téme?
  • V ktorej sekcii mám hľadať tému zo správy?

Môžeme samozrejme pokračovať v hľadaní vo všetkých sekciách, ale bude to veľmi smutné a zneguje to všetky naše výhry. Preto, aby sme vedeli, kde presne hľadať, vytvoríme logické odkazy/ukazovatele na sekcie:

  • doplníme do správy pole dátumu témy
  • doplníme k téme nastavený dátum správy táto korešpondencia (môže to byť samostatná tabuľka alebo pole dátumov)

Databáza Messenger (časť 2): rozdelenie „za účelom zisku“

Keďže pri každej jednotlivej korešpondencii dôjde k niekoľkým úpravám zoznamu dátumov správ (napokon takmer všetky správy pripadajú na 1-2 susedné dni), zameriam sa na túto možnosť.

Celkovo mala štruktúra našej databázy nasledujúcu formu, berúc do úvahy rozdelenie:

Tabuľky: RU, ak máte averziu voči azbuke v názvoch tabuliek/polí, radšej sa nepozerajte

-- секции по дате сообщения
CREATE TABLE "Сообщение_YYYYMMDD"(
  "Сообщение"
    uuid
      PRIMARY KEY
, "Тема"
    uuid
, "ДатаТемы"
    date
, "Автор"
    uuid
, "ДатаВремя" -- используем как дату
    timestamp
, "Текст"
    text
);

CREATE TABLE "Адресат_YYYYMMDD"(
  "ДатаСообщения"
    date
, "Сообщение"
    uuid
, "Персона"
    uuid
, PRIMARY KEY("Сообщение", "Персона")
);

CREATE TABLE "Файл_YYYYMMDD"(
  "ДатаСообщения"
    date
, "Файл"
    uuid
      PRIMARY KEY
, "Сообщение"
    uuid
, "BLOB"
    uuid
, "Имя"
    text
);

CREATE TABLE "РеестрСообщений_YYYYMMDD"(
  "ДатаСообщения"
    date
, "Владелец"
    uuid
, "ТипРеестра"
    smallint
, "ДатаВремя"
    timestamp
, "Сообщение"
    uuid
, PRIMARY KEY("Владелец", "ТипРеестра", "Сообщение")
);
CREATE INDEX ON "РеестрСообщений_YYYYMMDD"("Владелец", "ТипРеестра", "ДатаВремя" DESC);

-- секции по дате темы
CREATE TABLE "Тема_YYYYMMDD"(
  "ДатаТемы"
    date
, "Тема"
    uuid
      PRIMARY KEY
, "Документ"
    uuid
, "Название"
    text
);

CREATE TABLE "УчастникТемы_YYYYMMDD"(
  "ДатаТемы"
    date
, "Тема"
    uuid
, "Персона"
    uuid
, PRIMARY KEY("Тема", "Персона")
);

CREATE TABLE "ДатыСообщенийТемы_YYYYMMDD"(
  "ДатаТемы"
    date
, "Тема"
    uuid
      PRIMARY KEY
, "Дата"
    date
);

Ušetrite pekný cent

No, čo ak nepoužívame klasická možnosť delenia na základe distribúcie hodnôt polí (prostredníctvom spúšťačov a dedičnosti alebo PARTITION BY) a „ručne“ na úrovni aplikácie si všimnete, že hodnota rozdeľovacieho kľúča je už uložená v názve samotnej tabuľky.

Takže ak si taký Máte veľké obavy z množstva uložených dát?, potom sa môžete zbaviť týchto „extra“ polí a adresovať konkrétne tabuľky. Je pravda, že všetky výbery z niekoľkých sekcií sa v tomto prípade budú musieť preniesť na stranu aplikácie.

Zdroj: hab.com

Pridať komentár