Vi har framgÄngsrikt designat strukturen för vÄr PostgreSQL-databas för att lagra konversationer, ett Är har gÄtt, anvÀndarna fyller den aktivt, och den har redan miljontals poster, och⊠nÄgot har börjat hacka.
- Del 2: partitionera 'live'

Det handlar om att Med ökad tabellvolym ökar Ă€ven 'djupet' pĂ„ indexen â Ă€ven om det Ă€r i en logaritmisk takt. Men över tid tvingar det servern att hantera mycket fler datorsidor, Ă€n i början.
HÀr kommer hjÀlp frÄn partitionering.
Jag vill notera att vi inte pratar om sharding, det vill sÀga fördelning av data mellan olika databaser eller servrar. För Àven om du delar upp data pÄ nÄgra servrar, kommer du ÀndÄ inte undan problemet med 'uppblÄsta' index över tid. Det Àr klart att om du har möjlighet att sÀtta in en ny server varje dag, sÄ kommer dina problem att ligga i en helt annan dimension Àn den specifika databasen.
Vi kommer att titta pĂ„ inte konkreta skript för att implementera partitionering 'i hĂ„rdvara', utan sjĂ€lva tillvĂ€gagĂ„ngssĂ€ttet â vad och hur vi bör 'skĂ€ra i bitar', och vad detta önskemĂ„l leder till.
Koncept
LÄt oss Äterigen definiera vÄrt mÄl: vi vill göra sÄ att mÀngden lÀsta PostgreSQL-data vid vilken lÀsning/skrivning som helst förblir ungefÀr densamma idag, imorgon och om ett Är.
För alla data som samlas kronologiskt (meddelanden, dokument, loggar, arkiv, âŠ) Ă€r det naturliga valet av partitioneringsnyckel datum/tid för hĂ€ndelsen. I vĂ„rt fall Ă€r hĂ€ndelsen tillfĂ€llet för att skicka meddelandet.
Vi noterar att anvĂ€ndarna nĂ€stan alltid endast arbetar med de 'senaste' data â lĂ€ser de senaste meddelandena, analyserar de senaste loggarna,⊠Nej, sjĂ€lvklart kan de blĂ€ddra lĂ€ngre tillbaka i tiden, men de gör detta vĂ€ldigt sĂ€llan.
Av dessa begrĂ€nsningar blir det uppenbart att den optimala lösningen för meddelanden blir 'dagliga' sektioner â eftersom vĂ„r anvĂ€ndare nĂ€stan alltid kommer att lĂ€sa det som kom 'idag' eller 'i gĂ„r'.
Om vi under dagen skriver och lĂ€ser nĂ€stan enbart frĂ„n en sektion, ger det oss Ă€ven en mer effektiv anvĂ€ndning av minnet och disken â eftersom alla index i sektionen enkelt fĂ„r plats i minnet, till skillnad frĂ„n "stora och tjocka" över hela tabellen.
steg-för-steg
Allt som sagts ovan lĂ„ter som en enda stor vinst. Och det Ă€r uppnĂ„eligt, men för det mĂ„ste vi verkligen anstrĂ€nga oss â för att beslutet att sektionera en av enheterna krĂ€ver att vi "skĂ€r upp" relaterade.
Meddelandet, dess egenskaper och projektioner
Eftersom vi bestÀmde oss för att dela upp meddelanden efter datum, sÄ Àr det Àven rimligt att dela upp relaterade enheter-egenskaper (bilagor, lista över mottagare), och ocksÄ efter meddelandets datum.
Eftersom en av vÄra typiska uppgifter Àr att granska registren av meddelanden (olÀsta, mottagna, alla), sÄ Àr det ocksÄ logiskt att "dras in" i sektioneringen efter meddelandets datum.

Vi lÀgger till sektioneringsnyckeln (meddelandets datum) i alla tabeller: mottagare, fil, register. I sjÀlva meddelandet behöver vi inte lÀgga till detta, utan kan anvÀnda den befintliga DatumTid.
Ămnen
Eftersom temat Ă€r ett av flera meddelanden, sĂ„ gĂ„r det inte att "skĂ€ra" det i samma modell, vi mĂ„ste förlita oss pĂ„ nĂ„got annat. I vĂ„rt fall passar det perfekt med datumet för det första meddelandet i konversationen â det vill sĂ€ga ögonblicket av skapandet av just temat.

Vi lÀgger till sektioneringsnyckeln (temadatumet) i alla tabeller: tema, deltagare.
Men nu har vi plötsligt tvÄ problem:
- i vilken sektion ska vi leta efter meddelanden om temat?
- i vilken sektion ska vi leta efter temat frÄn meddelandet?
Vi kan naturligtvis fortsÀtta att söka i alla sektioner, men det skulle bli mycket trÄkigt och innebÀra att förlora alla vÄra vinster. DÀrför, för att veta exakt var vi ska leta, ska vi göra logiska lÀnkar/pekare till sektionerna:
- i meddelandet lÀgger vi till ett fÀlt med temat datum
- till temat lÀgger vi till ett set av meddelandedatum för denna konversation (kan vara en separat tabell eller en array av datum)

Eftersom modifieringarna av meddelandedatumlistan för varje enskild konversation kommer att vara fÄ (nÀstan alla meddelanden hamnar inom 1-2 angrÀnsande dagar), sÄ kommer jag att stanna vid just detta alternativ.
Sammanfattningsvis har strukturen av vÄr databas följande utseende med hÀnsyn till sektioneringen:
Tabeller: RU, om man har aversion mot kyrilliska bokstÀver i namn pÄ tabeller/fÀlt Àr det bÀttre att inte titta
-- sektioner efter meddelandedatum
CREATE TABLE "Meddelande_YYYYMMDD"(
"Meddelande"
uuid
PRIMARY KEY
, "Ămne"
uuid
, "DatumĂmne"
date
, "Författare"
uuid
, "DatumTid" -- anvÀnds som datum
timestamp
, "Text"
text
);
CREATE TABLE "Adressat_YYYYMMDD"(
"DatumMeddelande"
date
, "Meddelande"
uuid
, "Person"
uuid
, PRIMARY KEY("Meddelande", "Person")
);
CREATE TABLE "Fil_YYYYMMDD"(
"DatumMeddelande"
date
, "Fil"
uuid
PRIMARY KEY
, "Meddelande"
uuid
, "BLOB"
uuid
, "Namn"
text
);
CREATE TABLE "RegisterMeddelanden_YYYYMMDD"(
"DatumMeddelande"
date
, "Ăgare"
uuid
, "TypRegister"
smallint
, "DatumTid"
timestamp
, "Meddelande"
uuid
, PRIMARY KEY("Ăgare", "TypRegister", "Meddelande")
);
CREATE INDEX ON "RegisterMeddelanden_YYYYMMDD"("Ăgare", "TypRegister", "DatumTid" DESC);
-- sektioner efter Àmnesdatum
CREATE TABLE "Ămne_YYYYMMDD"(
"DatumĂmne"
date
, "Ămne"
uuid
PRIMARY KEY
, "Dokument"
uuid
, "Titel"
text
);
CREATE TABLE "DeltagareĂmne_YYYYMMDD"(
"DatumĂmne"
date
, "Ămne"
uuid
, "Person"
uuid
, PRIMARY KEY("Ămne", "Person")
);
CREATE TABLE "DatumMeddelandenĂmne_YYYYMMDD"(
"DatumĂmne"
date
, "Ămne"
uuid
PRIMARY KEY
, "Datum"
date
);
Sparar en slant
Men om vi inte anvÀnder baserat pÄ vÀrdefÀltets fördelning (genom triggers och arv eller PARTITION BY), utan "manuellt" pÄ applikationsnivÄ, kan vi mÀrka att vÀrdet av partitioneringsnyckeln redan lagras i tabellens namn.
SÄ om du Àr sÄ oroad över mÀngden lagrade data, kan vi bli av med dessa "överflödiga" fÀlt och adressera specifika tabeller. Dock kommer alla urval frÄn flera sektioner i detta fall att behöva flyttas till applikationen.
KĂ€lla: habr.com
