Messenger-datumbazo (parto 2): dispartigo "por profito"

Ni sukcese desegnis la strukturon de nia PostgreSQL-datumbazo por stoki korespondadon, jaro pasis, uzantoj aktive plenigas ĝin, kaj nun ĝi enhavas milionoj da rekordoj, kaj... io komencis malrapidiĝi.

Messenger-datumbazo (parto 2): dispartigo "por profito"
Punkto estas ke Ĉar la tabelgrandeco kreskas, ankaŭ kreskas la "profundo" de la indeksoj. - kvankam logaritme. Sed kun la tempo ĉi tio devigas la servilon plenumi la samajn lego/skribajn taskojn prilabori multajn fojojn pli da paĝoj de datumojol en la komenco.

Jen kie ĝi venas al la savo sekciado.

Mi rimarku, ke ni ne parolas pri sharding, tio estas, distribuado de datumoj inter malsamaj datumbazoj aŭ serviloj. Ĉar eĉ dividante la datumojn en pluraj serviloj, vi ne forigos la problemon de indeksoj "ŝvelantaj" kun la tempo. Estas klare, ke se vi povas pagi ĉiutage funkciigi novan servilon, tiam viaj problemoj tute ne kuŝos en la ebeno de specifa datumbazo.

Ni konsideros ne specifajn skriptojn por efektivigi dispartigon "en aparataro", sed la aliron mem - kio kaj kiel devus esti "tranĉita en tranĉaĵoj", kaj al kio tia deziro kondukas.

Koncepto

Ni difinu nian celon denove: ni volas certigi, ke hodiaŭ, morgaŭ kaj post jaro, la kvanto da datumoj legitaj de PostgreSQL dum iu ajn legado/skriba operacio restas proksimume sama.

Por iu ajn kronologie akumulitaj datumoj (mesaĝoj, dokumentoj, protokoloj, arkivoj, ...) la natura elekto kiel dispartiga ŝlosilo estas evento dato/tempo. En nia kazo, tia evento estas momento de sendo de la mesaĝo.

Notu, ke uzantoj preskaŭ ĉiam labori nur kun la "lastaj" tiuj tiaj datumoj - ili legas la lastajn mesaĝojn, analizas la lastajn protokolojn,... Ne, kompreneble, ili povas rulumi pli malantaŭen en la tempo, sed ili faras tion tre malofte.

De ĉi tiuj limoj estas klare, ke la optimuma mesaĝsolvo estus "ĉiutagaj" sekcioj - finfine nia uzanto preskaŭ ĉiam legos, kio venis al li "hodiaŭ" aŭ "hieraŭ".

Se ni skribas kaj legas preskaŭ nur en unu sekcio dum la tago, tiam ankaŭ ĉi tio donas al ni pli efika uzo de memoro kaj disko - ĉar ĉiuj sekciaj indeksoj facile konvenas en la RAM, kontraste al la "grandaj kaj dikaj" tra la tabelo.

paŝon post paŝo

Ĝenerale, ĉio dirita supre sonas kiel unu kontinua profito. Kaj ĝi estas atingebla, sed por tio ni devos klopodi — ĉar la decido dividi unu el la entoj kondukas al la bezono "vidi" la asociitajn.

Mesaĝo, ĝiaj propraĵoj kaj projekcioj

Ĉar ni decidis tranĉi mesaĝojn laŭ datoj, estas senco ankaŭ dividi la entojn-propraĵojn kiuj dependas de ili (aldonitaj dosieroj, listo de ricevantoj), kaj ankaŭ laŭ dato de mesaĝo.

Ĉar unu el niaj tipaj taskoj estas ĝuste vidi mesaĝregistrojn (nelegitaj, envenantaj, ĉiuj), estas ankaŭ logike "entiri ilin" en dispartigo laŭ mesaĝdatoj.

Messenger-datumbazo (parto 2): dispartigo "por profito"

Ni aldonas la dispartigan ŝlosilon (mesaĝa dato) al ĉiuj tabeloj: ricevantoj, dosiero, registroj. Vi ne devas aldoni ĝin al la mesaĝo mem, sed uzu la ekzistantan DateTime.

Temoj

Ĉar ekzistas nur unu temo por pluraj mesaĝoj, ne estas maniero "tranĉi" ĝin en la sama modelo; vi devas fidi al io alia. En nia kazo ĝi estas ideala dato de unua mesaĝo en korespondado — tio estas la momento de kreado, fakte, de la temo.

Messenger-datumbazo (parto 2): dispartigo "por profito"

Aldonu la dispartigan ŝlosilon (tema dato) al ĉiuj tabeloj: temo, partoprenanto.

Sed nun ni havas du problemojn samtempe:

  • En kiu sekcio mi serĉu mesaĝojn pri la temo?
  • En kiu sekcio mi serĉu la temon el la mesaĝo?

Ni povas, kompreneble, daŭrigi serĉi en ĉiuj sekcioj, sed ĉi tio estos tre malĝoja kaj neigos ĉiujn niajn gajnojn. Tial, por scii kie precize rigardi, ni faros logikaj ligiloj/montriloj al sekcioj:

  • ni aldonos en la mesaĝo temo dato kampo
  • ni aldonu al la temo mesaĝo dato fiksita ĉi tiu korespondado (povas esti aparta tabelo, aŭ aro da datoj)

Messenger-datumbazo (parto 2): dispartigo "por profito"

Ĉar estos malmultaj modifoj al la listo de mesaĝdatoj por ĉiu individua korespondado (finfine, preskaŭ ĉiuj mesaĝoj falas en 1-2 apudaj tagoj), mi koncentriĝos pri ĉi tiu opcio.

Entute, la strukturo de nia datumbazo prenis la sekvan formon, konsiderante dispartigo:

Tabeloj: RU, se vi havas malemon al la cirila alfabeto en la nomoj de tabeloj/kampoj, estas pli bone ne rigardi

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

Ŝparu belan pencon

Nu, kio se ni uzas ne klasika sekcia opcio surbaze de la distribuado de kampaj valoroj (per ellasiloj kaj heredo aŭ PARTITION BY), kaj "mane" ĉe la aplika nivelo, vi rimarkos, ke la valoro de la dispartiga ŝlosilo jam estas konservita en la nomo de la tabelo mem.

Do se vi estas tiel Ĉu vi tre zorgas pri la kvanto da datumoj stokitaj?, tiam vi povas forigi ĉi tiujn "ekstrajn" kampojn kaj trakti specifajn tabelojn. Vere, ĉiuj elektoj de pluraj sekcioj ĉi-kaze devos esti translokigitaj al la aplikaĵo.

fonto: www.habr.com

Aldoni komenton