Baza komunikatorów (część 2): partycjonowanie „dla zysku”

Udało nam się zaprojektować strukturę naszej bazy danych PostgreSQL do przechowywania korespondencji, minął rok, użytkownicy aktywnie ją wypełniają i teraz zawiera miliony rekordów, i... coś zaczęło zwalniać.

Baza komunikatorów (część 2): partycjonowanie „dla zysku”
Faktem jest, że Wraz ze wzrostem rozmiaru tabeli rośnie także „głębokość” indeksów. - aczkolwiek logarytmicznie. Jednak z biegiem czasu zmusza to serwer do wykonywania tych samych zadań odczytu/zapisu przetwarzać wielokrotnie więcej stron danychniż na początku.

Tutaj właśnie przychodzi na ratunek sekcje.

Zaznaczę, że nie mówimy tu o shardingu, czyli dystrybucji danych pomiędzy różnymi bazami danych czy serwerami. Ponieważ nawet podzielenie danych na kilka serwerów, nie pozbędziesz się problemu „puchnięcia” indeksów w czasie. Jasne jest, że jeśli stać Cię na codzienne uruchamianie nowego serwera, to Twoje problemy nie będą już w ogóle leżeć na płaszczyźnie konkretnej bazy danych.

Rozważymy nie konkretne skrypty implementujące partycjonowanie „sprzętowo”, ale samo podejście - co i jak należy „pociąć na plasterki” i do czego prowadzi taka chęć.

Koncepcja

Zdefiniujmy jeszcze raz nasz cel: chcemy mieć pewność, że dzisiaj, jutro i za rok ilość danych odczytywanych przez PostgreSQL podczas dowolnej operacji odczytu/zapisu pozostanie w przybliżeniu taka sama.

Dla każdego dane gromadzone chronologicznie (wiadomości, dokumenty, dzienniki, archiwa, ...) jest naturalnym wyborem jako klucz partycjonowania data/godzina wydarzenia. W naszym przypadku takim wydarzeniem jest moment wysłania wiadomości.

Należy pamiętać, że użytkownicy prawie zawsze pracuj tylko z „najnowszymi”. takie dane - czytają najnowsze wiadomości, analizują najnowsze logi,... Nie, oczywiście, mogą przewijać dalej w czasie, ale robią to bardzo rzadko.

Z tych ograniczeń jasno wynika, że ​​optymalnym rozwiązaniem byłoby przesyłanie komunikatów sekcje „codzienne”. - w końcu nasz użytkownik prawie zawsze przeczyta to, co przyszło mu do głowy „dziś” lub „wczoraj”.

Jeśli w ciągu dnia piszemy i czytamy prawie tylko w jednym dziale, to również nam to daje efektywniejsze wykorzystanie pamięci i dysku - ponieważ wszystkie indeksy sekcji z łatwością mieszczą się w pamięci RAM, w przeciwieństwie do „dużych i grubych” w całej tabeli.

krok po kroku

Ogólnie rzecz biorąc, wszystko, co powiedziano powyżej, brzmi jak jeden ciągły zysk. I jest to osiągalne, ale w tym celu będziemy musieli bardzo się postarać - ponieważ decyzja o podziale jednego z podmiotów pociąga za sobą konieczność „zobaczenia” podmiotu stowarzyszonego.

Przesłanie, jego właściwości i projekcje

Ponieważ zdecydowaliśmy się na wycinanie wiadomości według dat, warto podzielić także zależne od nich encje-właściwości (załączone pliki, lista odbiorców) i także według daty wiadomości.

Ponieważ jednym z naszych typowych zadań jest dokładne przeglądanie rejestrów wiadomości (nieprzeczytanych, przychodzących, wszystkich), logiczne jest również „wciągnięcie ich” w podział według dat wiadomości.

Baza komunikatorów (część 2): partycjonowanie „dla zysku”

Do wszystkich tabel: odbiorców, pliku, rejestrów dodajemy klucz partycjonowania (datę wiadomości). Nie musisz dodawać go do samej wiadomości, ale użyj istniejącej zmiennej DateTime.

wątki

Ponieważ na kilka wiadomości jest tylko jeden temat, nie ma możliwości „wycięcia” go w tym samym modelu, trzeba polegać na czymś innym. W naszym przypadku jest idealnie data pierwszej wiadomości w korespondencji — czyli właściwie moment powstania tematu.

Baza komunikatorów (część 2): partycjonowanie „dla zysku”

Dodaj klucz partycjonowania (data tematu) do wszystkich tabel: temat, uczestnik.

Ale teraz mamy dwa problemy na raz:

  • W jakim dziale mam szukać wiadomości na ten temat?
  • W jakim dziale mam szukać tematu z wiadomości?

Możemy oczywiście kontynuować wyszukiwanie we wszystkich sekcjach, ale będzie to bardzo smutne i zniweczy wszystkie nasze wygrane. Dlatego, żeby wiedzieć, gdzie dokładnie szukać, utworzymy logiczne linki/wskaźniki do sekcji:

  • dodamy w wiadomości pole daty tematu
  • dopiszmy do tematu ustawiona data wiadomości ta korespondencja (może być osobną tabelą lub tablicą dat)

Baza komunikatorów (część 2): partycjonowanie „dla zysku”

Ponieważ w przypadku każdej korespondencji będzie niewiele modyfikacji w wykazie dat wiadomości (w końcu prawie wszystkie wiadomości przypadają na 1-2 sąsiadujące ze sobą dni), skupię się na tej opcji.

W sumie struktura naszej bazy danych przy uwzględnieniu partycjonowania przyjęła następującą postać:

Tabele: RU, jeśli masz awersję do cyrylicy w nazwach tabel/pól, lepiej nie patrzeć

-- секции по дате сообщения
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
);

Zaoszczędź ładny grosz

A co jeśli nie użyjemy klasyczna opcja dzielenia w oparciu o rozkład wartości pól (poprzez wyzwalacze i dziedziczenie lub PARTITION BY) oraz „ręcznie” na poziomie aplikacji, zauważysz, że wartość klucza partycjonującego jest już zapisana w nazwie samej tabeli.

Więc jeśli tak jesteś Bardzo martwisz się ilością przechowywanych danych?, możesz pozbyć się tych „dodatkowych” pól i zająć się konkretnymi tabelami. To prawda, że ​​​​w tym przypadku wszystkie wybory z kilku sekcji będą musiały zostać przeniesione na stronę aplikacji.

Źródło: www.habr.com

Dodaj komentarz