Messenger-databas (del 2): ​​partitionering "för vinst"

Vi har framgångsrikt utformat strukturen för vår PostgreSQL-databas för att lagra korrespondens, ett år har gått, användare fyller aktivt i den och nu miljontals rekord, och ... något började sakta ner allt.

Messenger-databas (del 2): ​​partitionering "för vinst"
Faktum är att med tillväxten av tabellvolymen växer också "djupet" av indexen - om än logaritmiskt. Men med tiden tvingar det servern att göra samma läs-/skrivuppgifter bearbeta många gånger fler datasidorän i början.

Det är här det kommer till undsättning sektionering.

Jag noterar att det inte handlar om sharding, det vill säga distribution av data mellan olika databaser eller servrar. Eftersom även dividera data med flera servrar kommer du inte att bli av med problemet med "svällande" index över tiden. Det är klart att om du har råd att sätta en ny server i drift varje dag, kommer dina problem inte längre att ligga på planet för en viss databas.

Vi kommer inte att överväga specifika skript för att implementera partitionering "i hårdvara", utan själva tillvägagångssättet - vad och hur ska "skäras i skivor", och vad en sådan önskan leder till.

koncept

Återigen definierar vi vårt mål: vi vill se till att idag, imorgon och ett år senare, mängden data som läses av PostgreSQL för alla läs-/skrivoperationer förblir ungefär densamma.

För alla kronologiskt ackumulerade data (meddelanden, dokument, loggar, arkiv, ...) det naturliga valet för en partitionsnyckel är datum/tid för händelsen. I vårt fall är denna händelse i samma ögonblick som meddelandet skickades.

Observera att användare nästan alltid fungerar bara med det senaste sådana data - de läser de senaste meddelandena, analyserar de senaste loggarna, ... Nej, de kan naturligtvis scrolla längre tillbaka i tiden, bara de gör det väldigt sällan.

Av dessa begränsningar blir det uppenbart att den optimala lösningen för meddelanden kommer att vara "dagliga" avsnitt - trots allt kommer nästan alltid vår användare att läsa vad som kom till honom "idag" eller "igår".

Om vi ​​skriver och läser praktiskt taget bara i ett avsnitt under dagen, så ger detta oss också effektivare minne och diskanvändning - eftersom alla sektionsindex lätt passar in i RAM-minnet, till skillnad från de "stora och feta" i hela tabellen.

steg för steg

I allmänhet låter allt ovanstående som en enda stor vinst. Och det är möjligt, men för detta kommer vi att behöva arbeta hårt - eftersom beslutet att dela upp en av enheterna leder till behovet av att "såga" och associera.

Budskap, dess egenskaper och projektioner

Eftersom vi bestämde oss för att klippa meddelanden efter datum, är det också rimligt att dela upp entitetsegenskaperna beroende på dem (bifogade filer, lista över mottagare) och även efter postdatum.

Eftersom en av våra typiska uppgifter bara är att titta på meddelanderegistren (olästa, inkommande, alla), är det också logiskt att "rita" dem i sektionering efter meddelandedatum.

Messenger-databas (del 2): ​​partitionering "för vinst"

Vi lägger till partitionsnyckeln (meddelandedatum) till alla tabeller: mottagare, fil, register. Du kan inte lägga till i själva meddelandet, utan använda befintlig DateTime.

trådar

Eftersom ämnet är ett för flera meddelanden kommer det inte att vara möjligt att "klippa ut" det i samma modell, det är nödvändigt att lita på något annat. Perfekt för vårt fall. datum för det första meddelandet i korrespondensen - det vill säga skapelseögonblicket, faktiskt, av ämnet.

Messenger-databas (del 2): ​​partitionering "för vinst"

Lägg till en partitionsnyckel (ämnesdatum) till alla tabeller: ämne, medlem.

Men nu har vi två problem samtidigt:

  • i vilket avsnitt ska jag leta efter meddelanden om ämnet?
  • i vilket avsnitt ska man leta efter ämnet för meddelandet?

Du kan naturligtvis fortsätta att söka i alla sektioner, men det kommer att bli väldigt tråkigt och kommer att förneka alla våra vinster. Därför, för att veta exakt var vi ska leta, kommer vi att göra logiska länkar / pekare till avsnitt:

  • lägga till i meddelandet ämnesdatumfält
  • lägga till i ämnet meddelandedatum satt denna korrespondens (du kan använda en separat tabell eller så kan du använda en rad datum)

Messenger-databas (del 2): ​​partitionering "för vinst"

Eftersom det kommer att göras få ändringar av listan över meddelandedatum för varje enskild korrespondens (trots allt faller nästan alla meddelanden på 1-2 angränsande dagar), kommer jag att fokusera på detta alternativ.

Totalt tog strukturen av vår databas följande form, med hänsyn till partitionering:

Tabeller: RU

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

Spara en fin slant

Tja, tänk om vi använder klassisk sektionering. baserat på fördelningen av fältvärden (via triggers och arv eller PARTITION BY), men "manuellt" på applikationsnivå, kan du se att värdet på partitioneringsnyckeln redan är lagrat i själva tabellens namn.

Så om du är så är mycket oroliga för mängden lagrad data, då kan du bli av med dessa "extra" fält och adressera specifikt till specifika tabeller. Det är sant att alla val från flera sektioner i det här fallet redan måste överföras till applikationssidan.

Källa: will.com

Lägg en kommentar