Baza e të dhënave të Messenger (pjesa 2): ndarja "për fitim"

Ne kemi projektuar me sukses strukturën e bazës sonë të të dhënave PostgreSQL për ruajtjen e korrespondencës, ka kaluar një vit, përdoruesit po e plotësojnë atë në mënyrë aktive dhe tani ajo përmban miliona rekorde, dhe... diçka filloi të ngadalësohej.

Baza e të dhënave të Messenger (pjesa 2): ndarja "për fitim"
Fakti është se Ndërsa madhësia e tabelës rritet, rritet edhe "thellësia" e indekseve. - edhe pse logaritmikisht. Por me kalimin e kohës kjo e detyron serverin të kryejë të njëjtat detyra leximi/shkrimi përpunoni shumë herë më shumë faqe të dhënashse në fillim.

Këtu vjen puna për të shpëtuar seksionimi.

Më lejoni të vërej se nuk po flasim për ndarjen, domethënë shpërndarjen e të dhënave midis bazave të të dhënave ose serverëve të ndryshëm. Sepse edhe duke i ndarë të dhënat në несколько serverët, nuk do të shpëtoni nga problemi i "ënjtjes" së indekseve me kalimin e kohës. Është e qartë se nëse mund të përballoni të vendosni një server të ri në funksion çdo ditë, atëherë problemet tuaja nuk do të qëndrojnë fare në rrafshin e një baze të dhënash specifike.

Ne do të shqyrtojmë jo skriptet specifike për zbatimin e ndarjes "në harduer", por vetë qasjen - çfarë dhe si duhet "të pritet në feta" dhe në çfarë çon një dëshirë e tillë.

koncept

Le të përcaktojmë qëllimin tonë edhe një herë: ne duam të sigurohemi që sot, nesër dhe pas një viti, sasia e të dhënave të lexuara nga PostgreSQL gjatë çdo operacioni leximi/shkrimi të mbetet afërsisht e njëjtë.

Për çdo të dhëna të grumbulluara kronologjikisht (mesazhe, dokumente, regjistra, arkiva, ...) zgjedhja e natyrshme si një çelës ndarjeje është data/ora e ngjarjes. Në rastin tonë, një ngjarje e tillë është momenti i dërgimit të mesazhit.

Vini re se përdoruesit pothuajse gjithmonë punoni vetëm me ato "më të fundit". të dhëna të tilla - ata lexojnë mesazhet më të fundit, analizojnë regjistrat më të fundit,... Jo, sigurisht, ata mund të lëvizin më tej në kohë, por këtë e bëjnë shumë rrallë.

Nga këto kufizime është e qartë se zgjidhja optimale e mesazhit do të ishte seksionet "të përditshme". - në fund të fundit, përdoruesi ynë pothuajse gjithmonë do të lexojë atë që i erdhi "sot" ose "dje".

Nëse shkruajmë dhe lexojmë pothuajse vetëm në një pjesë gjatë ditës, atëherë edhe kjo na jep përdorim më efikas të memories dhe diskut - meqenëse të gjithë indekset e seksioneve përshtaten lehtësisht në RAM, në kontrast me ato "të mëdha dhe të majme" në të gjithë tabelën.

hap pas hapi

Në përgjithësi, gjithçka që u tha më sipër tingëllon si një fitim i vazhdueshëm. Dhe është e arritshme, por për këtë do të duhet të përpiqemi shumë - sepse vendimi për ndarjen e njërit prej subjekteve çon në nevojën për të "parë" të lidhur.

Mesazhi, vetitë dhe parashikimet e tij

Meqenëse vendosëm të shkurtojmë mesazhet sipas datave, ka kuptim të ndajmë edhe entitetet-vetitë që varen prej tyre (skedarët e bashkangjitur, lista e marrësve) dhe edhe sipas datës së mesazhit.

Meqenëse një nga detyrat tona tipike është pikërisht shikimi i regjistrave të mesazheve (të palexuara, të ardhura, të gjithë), është gjithashtu logjike t'i "tërheqim" në ndarjen sipas datave të mesazheve.

Baza e të dhënave të Messenger (pjesa 2): ndarja "për fitim"

Ne shtojmë çelësin e ndarjes (datën e mesazhit) në të gjitha tabelat: marrësit, skedarët, regjistrat. Nuk duhet ta shtoni në vetë mesazhin, por përdorni datën ekzistuese.

Temat

Meqenëse ka vetëm një temë për disa mesazhe, nuk ka asnjë mënyrë për ta "prerë" atë në të njëjtin model; duhet të mbështeteni në diçka tjetër. Në rastin tonë është ideale data e mesazhit të parë në korrespondencë — pra momenti i krijimit, në fakt, i temës.

Baza e të dhënave të Messenger (pjesa 2): ndarja "për fitim"

Shtoni çelësin e ndarjes (datën e temës) në të gjitha tabelat: temë, pjesëmarrës.

Por tani kemi dy probleme njëherësh:

  • Në cilin seksion duhet të kërkoj mesazhe mbi temën?
  • Në cilin seksion duhet të kërkoj temën nga mesazhi?

Sigurisht, ne mund të vazhdojmë të kërkojmë në të gjitha seksionet, por kjo do të jetë shumë e trishtueshme dhe do të mohojë të gjitha fitimet tona. Prandaj, për të ditur se ku të shikojmë saktësisht, ne do të bëjmë lidhje/tregues logjikë për seksionet:

  • do të shtojmë në mesazh fusha e datës së temës
  • t'i shtohemi temës është caktuar data e mesazhit kjo korrespondencë (mund të jetë një tabelë e veçantë, ose një grup datash)

Baza e të dhënave të Messenger (pjesa 2): ndarja "për fitim"

Meqenëse do të ketë pak modifikime në listën e datave të mesazheve për secilën korrespondencë individuale (në fund të fundit, pothuajse të gjitha mesazhet bien në 1-2 ditë ngjitur), unë do të përqendrohem në këtë opsion.

Në total, struktura e bazës sonë të të dhënave mori formën e mëposhtme, duke marrë parasysh ndarjen:

Tabelat: RU, nëse keni një neveri ndaj alfabetit cirilik në emrat e tabelave / fushave, është më mirë të mos shikoni

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

Kurseni një qindarkë të bukur

Epo, po sikur të mos përdorim opsioni klasik i seksionit bazuar në shpërndarjen e vlerave të fushës (përmes nxitësve dhe trashëgimisë ose PARTITION BY), dhe "manualisht" në nivelin e aplikacionit, do të vini re se vlera e çelësit të ndarjes është ruajtur tashmë në emrin e vetë tabelës.

Pra, nëse jeni kështu Jeni shumë i shqetësuar për sasinë e të dhënave të ruajtura?, atëherë mund të hiqni qafe këto fusha "shtesë" dhe të adresoni tabela specifike. Vërtetë, të gjitha zgjedhjet nga disa seksione në këtë rast do të duhet të transferohen në anën e aplikacionit.

Burimi: www.habr.com

Shto një koment