Databáze Messenger (část 2): rozdělení „za účelem zisku“

Úspěšně jsme navrhli strukturu naší PostgreSQL databáze pro ukládání korespondence, uplynul rok, uživatelé ji aktivně plní a nyní obsahuje miliony záznamů, a... něco se začalo zpomalovat.

Databáze Messenger (část 2): rozdělení „za účelem zisku“
Faktem je, že S rostoucí velikostí tabulky roste i „hloubka“ indexů. - i když logaritmicky. Postupem času to ale server nutí provádět stejné úlohy čtení/zápisu zpracovat mnohonásobně více stránek datnež na začátku.

Tady jde o záchranu dělení.

Dovolte mi poznamenat, že nemluvíme o shardingu, tedy o distribuci dat mezi různé databáze nebo servery. Protože i dělení dat do někteří se časem nezbavíte problému „bobtnání“ indexů. Je jasné, že pokud si můžete dovolit každý den zprovozňovat nový server, vaše problémy už nebudou vůbec ležet v rovině konkrétní databáze.

Nebudeme zvažovat konkrétní skripty pro implementaci rozdělení „v hardwaru“, ale samotný přístup - co a jak by mělo být „nakrájeno na plátky“ a k čemu taková touha vede.

Pojem

Pojďme si ještě jednou definovat náš cíl: chceme se ujistit, že dnes, zítra a za rok zůstane množství dat přečtených PostgreSQL během jakékoli operace čtení/zápisu přibližně stejné.

Pro jakékoli chronologicky nashromážděná data (zprávy, dokumenty, protokoly, archivy, ...) je přirozenou volbou rozdělovacího klíče datum/čas události. V našem případě taková událost je okamžik odeslání zprávy.

Všimněte si, že uživatelé téměř vždy pracovat pouze s těmi „nejnovějšími“. taková data – čtou nejnovější zprávy, analyzují nejnovější protokoly,... Ne, samozřejmě, mohou se posouvat dále v čase, ale dělají to velmi zřídka.

Z těchto omezení je zřejmé, že optimální řešení zpráv by bylo „denní“ úseky - náš uživatel si totiž téměř vždy přečte, co mu přišlo „dnes“ nebo „včera“.

Pokud během dne píšeme a čteme téměř jen v jednom úseku, pak nám to také dává efektivnější využití paměti a disku - protože všechny indexy sekcí se snadno vejdou do paměti RAM, na rozdíl od „velkých a tlustých“ v celé tabulce.

krok za krokem

Obecně platí, že vše výše uvedené zní jako jeden nepřetržitý zisk. A je to dosažitelné, ale o to se budeme muset hodně snažit – protože rozhodnutí o rozdělení jedné z entit vede k potřebě „vidět“ přidružené.

Zpráva, její vlastnosti a projekce

Vzhledem k tomu, že jsme se rozhodli ořezat zprávy podle dat, má smysl rozdělit také entity-vlastnosti, které na nich závisí (připojené soubory, seznam příjemců) a také podle data zprávy.

Protože jedním z našich typických úkolů je přesné prohlížení registrů zpráv (nepřečtených, příchozích, všech), je také logické je „vtáhnout“ do rozdělení podle data zpráv.

Databáze Messenger (část 2): rozdělení „za účelem zisku“

Rozdělovací klíč (datum zprávy) přidáme do všech tabulek: příjemci, soubor, registry. Nemusíte jej přidávat do samotné zprávy, ale použijte existující DateTime.

nitě

Vzhledem k tomu, že existuje pouze jedno téma pro několik zpráv, neexistuje způsob, jak je „seknout“ ve stejném modelu, musíte se spolehnout na něco jiného. V našem případě je to ideální datum první zprávy v korespondenci — tedy okamžik vzniku, vlastně tématu.

Databáze Messenger (část 2): rozdělení „za účelem zisku“

Přidejte rozdělovací klíč (datum tématu) do všech tabulek: téma, účastník.

Ale teď máme dva problémy najednou:

  • Ve které sekci mám hledat zprávy k tématu?
  • Ve které sekci mám hledat téma ze zprávy?

Můžeme samozřejmě pokračovat v hledání ve všech sekcích, ale bude to velmi smutné a bude to negovat všechny naše výhry. Proto, abychom věděli, kde přesně hledat, vytvoříme logické odkazy/ukazatele na sekce:

  • doplníme do zprávy pole data tématu
  • doplníme k tématu nastaveno datum zprávy tato korespondence (může to být samostatná tabulka nebo pole dat)

Databáze Messenger (část 2): rozdělení „za účelem zisku“

Vzhledem k tomu, že pro každou jednotlivou korespondenci dojde k několika málo úpravám seznamu dat zpráv (ostatně téměř všechny zprávy připadají na 1-2 sousední dny), zaměřím se na tuto možnost.

Celkově měla struktura naší databáze s přihlédnutím k rozdělení na oddíly následující podobu:

Tabulky: RU, pokud máte odpor k azbuce v názvech tabulek/polí, raději nehledejte

-- секции по дате сообщения
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šetřete pěkný peníz

No, co když nepoužíváme možnost klasického dělení na základě distribuce hodnot polí (prostřednictvím spouštěčů a dědičnosti nebo PARTITION BY) a „ručně“ na úrovni aplikace si všimnete, že hodnota rozdělovacího klíče je již uložena v názvu samotné tabulky.

Pokud tedy jste Máte velké obavy z množství uložených dat?, pak se můžete zbavit těchto „extra“ polí a adresovat konkrétní tabulky. Je pravda, že všechny výběry z několika sekcí v tomto případě budou muset být přeneseny na stranu aplikace.

Zdroj: www.habr.com

Přidat komentář