Olemme suunnitelleet onnistuneesti PostgreSQL-tietokantamme rakenteen kirjeenvaihtoa varten, vuosi on kulunut, käyttäjät täyttävät sitä aktiivisesti ja nyt se sisältää miljoonia levyjä, ja... jokin alkoi hidastua.
Tosiasia on, että Taulukon koon kasvaessa indeksien "syvyys" kasvaa. - tosin logaritmisesti. Mutta ajan myötä tämä pakottaa palvelimen suorittamaan samat luku-/kirjoitustehtävät käsittelee monta kertaa enemmän datasivujakuin alussa.
Tässä se tulee apuun leikkaus.
Haluan huomauttaa, että emme puhu shardingista, eli tietojen jakamisesta eri tietokantojen tai palvelimien välillä. Koska jopa tietojen jakaminen useat palvelimia, et pääse eroon indeksien "turpoamisesta" ajan myötä. On selvää, että jos sinulla on varaa ottaa uusi palvelin käyttöön joka päivä, ongelmasi eivät ole enää lainkaan tietyn tietokannan tasolla.
Emme harkitse erityisiä skriptejä osioinnin toteuttamiseksi "laitteistossa", vaan itse lähestymistapaa - mitä ja miten tulisi "leikata viipaleiksi", ja mihin tällainen halu johtaa.
käsite
Määrittelemme tavoitteemme vielä kerran: haluamme varmistaa, että tänään, huomenna ja vuoden kuluttua PostgreSQL:n lukema datamäärä pysyy suunnilleen samana luku-/kirjoitusoperaatioiden aikana.
Mille tahansa kronologisesti kertyneet tiedot (viestit, asiakirjat, lokit, arkistot, ...) luonnollinen valinta osiointiavaimeksi on tapahtuman päivämäärä/aika. Meidän tapauksessamme tällainen tapahtuma on viestin lähettämisen hetki.
Huomaa, että käyttäjät melkein aina työskentele vain "uusimpien" kanssa sellaisia tietoja - he lukevat uusimmat viestit, analysoivat uusimmat lokit,... Ei, tietenkään, he voivat vierittää ajassa taaksepäin, mutta he tekevät tämän hyvin harvoin.
Näistä rajoituksista on selvää, että optimaalinen viestiratkaisu olisi "päivittäiset" osiot - loppujen lopuksi käyttäjämme lukee melkein aina, mitä hänelle tuli "tänään" tai "eilen".
Jos kirjoitamme ja luemme melkein vain yhdessä osiossa päivän aikana, tämä myös antaa meille muistin ja levyn tehokkaampi käyttö - koska kaikki osioindeksit mahtuvat helposti RAM-muistiin, toisin kuin "isot ja lihavat" koko taulukossa.
askel-askeleelta
Yleisesti ottaen kaikki edellä sanottu kuulostaa yhdeltä jatkuvalta voitolta. Ja se on saavutettavissa, mutta tätä varten meidän on yritettävä kovasti - koska päätös osioida yksi kokonaisuudesta johtaa tarpeeseen "nähdä" siihen liittyvä.
Viesti, sen ominaisuudet ja projektiot
Koska päätimme leikata viestejä päivämäärien mukaan, on järkevää jakaa myös niistä riippuvat entiteetit-ominaisuudet (liitetiedostot, vastaanottajaluettelo) ja myös viestin päivämäärän mukaan.
Koska yksi tyypillisistä tehtävistämme on juuri viestirekisterien tarkastelu (lukemattomat, saapuvat, kaikki), on myös loogista "vetää ne sisään" osiointiin viestipäivämäärän mukaan.
Lisäämme osiointiavaimen (viestin päivämäärä) kaikkiin taulukoihin: vastaanottajat, tiedosto, rekisterit. Sinun ei tarvitse lisätä sitä itse viestiin, vaan käytä olemassa olevaa DateTimea.
Aiheet
Koska useille viesteille on vain yksi aihe, sitä ei voi "leikata" samaan malliin, vaan täytyy luottaa johonkin muuhun. Meidän tapauksessamme se on ihanteellinen ensimmäisen kirjeenvaihtoviestin päivämäärä - eli itse asiassa aiheen luomisen hetki.
Lisää osiointiavain (aiheen päivämäärä) kaikkiin taulukoihin: aihe, osallistuja.
Mutta nyt meillä on kaksi ongelmaa kerralla:
Mistä osiosta minun pitäisi etsiä aiheeseen liittyviä viestejä?
Mistä osiosta minun pitäisi etsiä aihetta viestistä?
Voimme tietysti jatkaa hakua kaikissa osissa, mutta tämä on erittäin surullista ja mitätöi kaikki voittomme. Siksi, jotta tiedämme, mistä tarkalleen etsiä, teemme loogisia linkkejä/osoittimia osioihin:
lisäämme viestiin aiheen päivämäärä -kenttä
lisätään aiheeseen viestin päivämäärä asetettu tämä kirjeenvaihto (voi olla erillinen taulukko tai joukko päivämääriä)
Koska jokaisen yksittäisen kirjeenvaihdon viestipäivämääräluetteloon tulee vähän muutoksia (lähes kaikki viestit osuvat 1-2 vierekkäiselle päivälle), keskityn tähän vaihtoehtoon.
Kaiken kaikkiaan tietokantamme rakenne oli seuraavanlainen ottaen huomioon osiointi:
Taulukot: RU, jos suhtaudut vastenmielisyyteen kyrillisiä aakkosia kohtaan taulukoiden/kenttien nimissä, on parempi olla katsomatta
-- секции по дате сообщения
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
);
Säästä kaunis penni
Entä jos emme käytä klassinen leikkausvaihtoehto kenttäarvojen jakautumisen perusteella (triggerien ja periytymisen tai PARTITION BY:n kautta) ja "manuaalisesti" sovellustasolla, huomaat, että osiointiavaimen arvo on jo tallennettu itse taulukon nimeen.
Joten jos olet niin Oletko erittäin huolissasi tallennetun datan määrästä?, voit päästä eroon näistä "ylimääräisistä" kentistä ja osoittaa tiettyjä taulukoita. Totta, kaikki valinnat useista osioista on tässä tapauksessa siirrettävä sovelluspuolelle.