ProHoster > Blog > uprava > Messenger baza podataka (2. dio): particioniranje “za profit”
Messenger baza podataka (2. dio): particioniranje “za profit”
Uspješno smo dizajnirali strukturu naše PostgreSQL baze podataka za pohranjivanje korespondencije, prošla je godina dana, korisnici je aktivno popunjavaju, a sada sadrži milijuni zapisa, i... nešto je počelo usporavati.
Činjenica je da Kako raste veličina tablice, tako raste i "dubina" indeksa. - iako logaritamski. Ali s vremenom to prisiljava poslužitelj da obavlja iste zadatke čitanja/pisanja obraditi višestruko više stranica podatakanego na početku.
Tu dolazi u pomoć sekcioniranje.
Napominjem da ne govorimo o šardingu, odnosno distribuciji podataka između različitih baza podataka ili poslužitelja. Jer čak i dijeljenje podataka na više poslužitelja, nećete se riješiti problema "bubrenja" indeksa tijekom vremena. Jasno je da ako si možete priuštiti puštanje u rad novog poslužitelja svaki dan, onda vaši problemi više uopće neće ležati u ravni određene baze podataka.
Nećemo razmatrati specifične skripte za implementaciju particioniranja "u hardveru", već sam pristup - što i kako treba "izrezati na kriške" i čemu takva želja vodi.
Koncept
Definirajmo još jednom naš cilj: želimo biti sigurni da će danas, sutra i za godinu dana količina podataka koje PostgreSQL pročita tijekom bilo koje operacije čitanja/pisanja ostati približno ista.
Za bilo koje kronološki prikupljeni podaci (poruke, dokumenti, zapisnici, arhive, ...) prirodan izbor kao particioni ključ je datum/vrijeme događaja. U našem slučaju takav je događaj trenutku slanja poruke.
Imajte na umu da korisnici gotovo uvijek raditi samo s "najnovijim". takve podatke - čitaju najnovije poruke, analiziraju najnovije zapise,... Ne, naravno, mogu se pomicati dalje u prošlost, ali to čine vrlo rijetko.
Iz ovih ograničenja jasno je da bi optimalno rješenje poruke bilo "dnevne" rubrike - uostalom, naš će korisnik gotovo uvijek pročitati ono što mu je došlo “danas” ili “jučer”.
Ako tijekom dana pišemo i čitamo gotovo samo u jednom dijelu, onda nam i to daje učinkovitije korištenje memorije i diska - budući da svi indeksi sekcija lako stanu u RAM, za razliku od onih "velikih i debelih" u cijeloj tablici.
korak po korak
Općenito, sve gore rečeno zvuči kao jedan kontinuirani profit. I to je ostvarivo, ali za ovo ćemo se morati dobro potruditi – jer odluka o podjeli jednog od entiteta dovodi do potrebe da se "prepili" povezano.
Poruka, njezina svojstva i projekcije
Budući da smo odlučili poruke rezati po datumima, ima smisla podijeliti i entitete-svojstva koja o njima ovise (priložene datoteke, popis primatelja), i također prema datumu poruke.
Budući da je jedan od naših tipičnih zadataka upravo pregled registara poruka (nepročitanih, dolaznih, svih), također je logično da ih “uvučemo” u particiju po datumima poruka.
Dodajemo particioni ključ (datum poruke) u sve tablice: primatelji, datoteka, registri. Ne morate ga dodati u samu poruku, već koristite postojeći DateTime.
Teme
Budući da postoji samo jedna tema za nekoliko poruka, nema načina da je “srežete” u istom modelu, morate se osloniti na nešto drugo. U našem slučaju to je idealno datum prve poruke u korespondenciji — odnosno trenutak nastanka, zapravo, teme.
Dodajte particioni ključ (datum teme) svim tablicama: tema, sudionik.
Ali sada imamo dva problema odjednom:
U kojem odjeljku trebam tražiti poruke o temi?
U kojoj rubrici da tražim temu iz poruke?
Možemo, naravno, nastaviti tražiti u svim odjeljcima, ali to će biti vrlo tužno i poništit će sve naše dobitke. Stoga, kako bismo znali gdje točno tražiti, napravit ćemo logične poveznice/pokazivače na odjeljke:
dodat ćemo u poruci polje datuma teme
dopunimo temu postavljen datum poruke ovo dopisivanje (može biti zasebna tablica ili niz datuma)
Budući da će biti nekoliko izmjena na popisu datuma poruka za svaku pojedinačnu korespondenciju (uostalom, gotovo sve poruke padaju na 1-2 susjedna dana), usredotočit ću se na ovu opciju.
Ukupno je struktura naše baze podataka imala sljedeći oblik, uzimajući u obzir particije:
Tablice: RU, ako imaš averziju prema ćirilici u nazivima tabela/polja, bolje da ne gledaš
-- секции по дате сообщения
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štedite priličan novčić
Pa, što ako ne koristimo klasična opcija rezanja na temelju distribucije vrijednosti polja (putem okidača i nasljeđivanja ili PARTITION BY), te “ručno” na razini aplikacije, primijetit ćete da je vrijednost particionog ključa već pohranjena u nazivu same tablice.
Pa ako ste tako Jeste li jako zabrinuti zbog količine pohranjenih podataka?, tada se možete riješiti ovih "dodatnih" polja i adresirati određene tablice. Istina, svi odabiri iz nekoliko odjeljaka u ovom slučaju morat će se prenijeti na stranu aplikacije.