Postgres: bloat, pg_repack og deferred constraints

Postgres: bloat, pg_repack og deferred constraints

Effekten af ​​oppustet tabeller og indekser (bloat) er almindeligt kendt og er til stede ikke kun i Postgres. Der er måder at håndtere det "ud af kassen" som VACUUM FULL eller CLUSTER, men de låser borde under drift og kan derfor ikke altid bruges.

Artiklen vil have nogle teorier om, hvordan oppustethed opstår, hvordan du kan håndtere det, om udskudte begrænsninger og de problemer, de medfører ved brug af pg_repack-udvidelsen.

Denne artikel er baseret på min tale på PgConf.Russia 2020.

Hvorfor er der en oppustethed

Postgres er baseret på en multi-version model (MVCC). Dens essens er, at hver række i tabellen kan have flere versioner, mens transaktioner ikke ser mere end én af disse versioner, men ikke nødvendigvis den samme. Dette tillader flere transaktioner at arbejde samtidigt og har ringe eller ingen effekt på hinanden.

Det er klart, at alle disse versioner skal beholdes. Postgres arbejder med hukommelse side for side, og en side er den mindste mængde data, der kan læses fra disk eller skrives. Lad os se på et lille eksempel for at forstå, hvordan dette sker.

Lad os sige, at vi har en tabel, som vi har tilføjet flere poster til. Den første side i filen, hvor tabellen er gemt, har nye data. Disse er liveversioner af rækker, der er tilgængelige for andre transaktioner efter commit (for nemheds skyld antager vi, at isolationsniveauet er Read Committed).

Postgres: bloat, pg_repack og deferred constraints

Vi opdaterede derefter en af ​​posterne og markerede dermed den gamle version som forældet.

Postgres: bloat, pg_repack og deferred constraints

Trin for trin, opdatering og sletning af rækkeversioner, fik vi en side, hvor omkring halvdelen af ​​dataene er "skrald". Disse data er ikke synlige for nogen transaktion.

Postgres: bloat, pg_repack og deferred constraints

Postgres har en mekanisme VACUUM, som rydder op i forældede versioner og giver plads til nye data. Men hvis den ikke er konfigureret aggressivt nok eller har travlt med at arbejde i andre tabeller, så forbliver "skraldedataene", og vi er nødt til at bruge yderligere sider til nye data.

Så i vores eksempel vil tabellen på et tidspunkt bestå af fire sider, men der vil kun være halvdelen af ​​live-dataene i den. Som et resultat vil vi, når vi får adgang til tabellen, læse meget flere data op end nødvendigt.

Postgres: bloat, pg_repack og deferred constraints

Selvom VACUUM nu fjerner alle irrelevante rækkeversioner, vil situationen ikke forbedres dramatisk. Vi vil have ledig plads i sider eller endda hele sider til nye linjer, men vi vil stadig læse mere data, end vi har brug for.
Forresten, hvis en helt tom side (den anden i vores eksempel) var i slutningen af ​​filen, så kunne VACUUM skære den af. Men nu er hun i midten, så hende kan der ikke gøres noget ved.

Postgres: bloat, pg_repack og deferred constraints

Når antallet af sådanne tomme eller meget sparsomme sider bliver stort, hvilket kaldes bloat, begynder det at påvirke ydeevnen.

Alt beskrevet ovenfor er mekanikken for forekomsten af ​​oppustethed i tabeller. I indekser sker dette stort set på samme måde.

Har jeg en oppustethed?

Der er flere måder at afgøre, om du har en oppustethed. Ideen med den første er at bruge Postgres interne statistik, som indeholder omtrentlige oplysninger om antallet af rækker i tabeller, antallet af "live" rækker osv. Der findes mange variationer af færdige scripts på internettet. Vi tog udgangspunkt i manuskript fra PostgreSQL Experts, som kan evaluere bordbloat sammen med toast og bloat btree-indekser. Vores erfaring er, at fejlen er 10-20%.

En anden måde er at bruge udvidelsen pgstattuple, som giver dig mulighed for at kigge inde på siderne og få både den estimerede og den nøjagtige værdi af bloat. Men i det andet tilfælde bliver du nødt til at scanne hele bordet.

En lille mængde oppustethed, op til 20 %, er acceptabel. Det kan betragtes som en analog af fillfactor for tabeller и indekser. Ved 50 % og derover kan ydeevneproblemer begynde.

Måder at håndtere oppustethed

Der er flere out-of-the-box måder at håndtere oppustethed på i Postgres, men de er langt fra altid og passer måske ikke alle.

Indstil AUTOVACUUM, så der ikke opstår oppustethed. Og for at være mere præcis, at holde det på et acceptabelt niveau for dig. Dette virker som et "kaptajns" råd, men i virkeligheden er det ikke altid nemt at opnå. For eksempel har du en aktiv udvikling med en regelmæssig ændring i dataskemaet, eller der finder en form for datamigrering sted. Som følge heraf kan din belastningsprofil ændres ofte og har tendens til at være forskellig for forskellige tabeller. Det betyder, at du hele tiden skal være lidt foran kurven og justere AUTOVACUUM til den skiftende profil på hvert bord. Men det er indlysende, at det ikke er let at gøre.

En anden almindelig årsag til, at AUTOVACUUM undlader at behandle tabeller, er tilstedeværelsen af ​​langvarige transaktioner, der forhindrer det i at rydde op i data på grund af det faktum, at det er tilgængeligt for disse transaktioner. Anbefalingen her er også oplagt - slip for "hængende" transaktioner og minimer tiden for aktive transaktioner. Men hvis belastningen på din applikation er en hybrid af OLAP og OLTP, så kan du samtidig have både en masse hyppige opdateringer og korte forespørgsler og langsigtede operationer - for eksempel at bygge en rapport. I en sådan situation bør du tænke på at sprede belastningen på forskellige baser, hvilket giver dig mulighed for at finjustere hver af dem.

Et andet eksempel - selvom profilen er homogen, men databasen er under en meget høj belastning, så kan selv den mest aggressive AUTOVACUUM muligvis ikke klare sig, og der vil opstå oppustethed. Skalering (lodret eller vandret) er den eneste løsning.

Hvordan man er i en situation, når du konfigurerede AUTOVACUUM, men oppustethed fortsætter med at vokse.

Team VAKUUM FULD genopbygger indholdet af tabeller og indekser og efterlader kun opdaterede data i dem. For at eliminere oppustethed fungerer det perfekt, men under dets udførelse fanges en eksklusiv lås på bordet (AccessExclusiveLock), som ikke vil tillade forespørgsler til denne tabel, selv vælgere. Hvis du har råd til at stoppe din tjeneste eller en del af den i nogen tid (fra snesevis af minutter til flere timer afhængigt af størrelsen på databasen og din hardware), så er denne mulighed den bedste. Vi har desværre ikke tid til at køre VACUUM FULL under den planlagte vedligeholdelse, så denne metode passer ikke os.

Team CLUSTER genopbygger indholdet af tabeller på samme måde som VACUUM FULL, samtidig med at du kan angive et indeks, hvorefter dataene fysisk vil blive ordnet på disken (men rækkefølgen er ikke garanteret for nye rækker i fremtiden). I visse situationer er dette en god optimering til en række forespørgsler - med læsning af flere poster i indekset. Ulempen ved kommandoen er den samme som ved VACUUM FULL - den låser bordet under drift.

Team REINDEKS ligner de to foregående, men genopbygger et specifikt indeks eller alle indekser på en tabel. Låse er lidt svagere: ShareLock på en tabel (forhindrer ændringer, men tillader udvalgte) og AccessExclusiveLock på et genopbyggeligt indeks (blokerer forespørgsler ved hjælp af dette indeks). Postgres 12 introducerede dog muligheden SAMMELIGT, som giver dig mulighed for at genopbygge et indeks uden at blokere samtidig tilføjelse, ændring eller sletning af poster.

I tidligere versioner af Postgres kan du opnå et resultat, der ligner REINDEX SAMMENLIGT med OPRET INDEKS SAMTIDIGT. Det giver dig mulighed for at oprette et indeks uden en stærk lås (ShareUpdateExclusiveLock, som ikke forstyrrer parallelle forespørgsler), derefter erstatte det gamle indeks med et nyt og slette det gamle indeks. Dette giver dig mulighed for at eliminere indeksbloat uden at forstyrre din applikation. Det er vigtigt at overveje, at når du genopbygger indekser, vil der være en ekstra belastning på diskundersystemet.

Således, hvis der er måder, hvorpå indekser kan eliminere hot bloat, så er der ingen til tabeller. Det er her, eksterne udvidelser kommer i spil: pg_repack (tidligere pg_reorg), pgcompact, pgcompacttable og andre. Inden for rammerne af denne artikel vil jeg ikke sammenligne dem og vil kun tale om pg_repack, som vi efter lidt forfining bruger derhjemme.

Hvordan pg_repack virker

Postgres: bloat, pg_repack og deferred constraints
Lad os sige, at vi har en ganske almindelig tabel - med indekser, restriktioner og desværre med oppustethed. Som et første trin opretter pg_repack en logtabel for at holde styr på alle ændringer, mens den kører. Udløseren vil replikere disse ændringer til hver indsættelse, opdatering og sletning. Derefter oprettes en tabel, der ligner originalen i strukturen, men uden indekser og begrænsninger, for ikke at bremse processen med at indsætte data.

Dernæst overfører pg_repack data fra den gamle tabel til den nye tabel, filtrerer automatisk alle irrelevante rækker ud og opretter derefter indekser til den nye tabel. Under udførelsen af ​​alle disse operationer akkumuleres ændringer i logtabellen.

Det næste trin er at overføre ændringerne til den nye tabel. Migreringen udføres i flere iterationer, og når der er mindre end 20 poster tilbage i logtabellen, får pg_repack en stærk lås, migrerer de seneste data og erstatter den gamle tabel med den nye i Postgres systemtabellerne. Dette er det eneste og meget korte tidspunkt, hvor du ikke vil være i stand til at arbejde med bordet. Derefter slettes den gamle tabel og tabellen med logfiler, og der frigøres plads i filsystemet. Processen afsluttet.

I teorien ser alt godt ud, men hvad med i praksis? Vi testede pg_repack uden belastning og under belastning, og kontrollerede dens funktion i tilfælde af et for tidligt stop (med andre ord med Ctrl+C). Alle prøver var positive.

Vi gik til prod - og så gik alt galt, som vi havde forventet.

Første pandekage til salg

På den første klynge fik vi en fejl om en unik overtrædelse af begrænsninger:

$ ./pg_repack -t tablename -o id
INFO: repacking table "tablename"
ERROR: query failed: 
    ERROR: duplicate key value violates unique constraint "index_16508"
DETAIL:  Key (id, index)=(100500, 42) already exists.

Denne begrænsning havde det autogenererede navn index_16508, oprettet af pg_repack. Ud fra de attributter, der er inkluderet i dens sammensætning, bestemte vi "vores" begrænsning, der svarer til den. Problemet viste sig at være, at dette ikke er en helt almindelig begrænsning, men en forsinket (udskudt begrænsning), dvs. dens validering udføres senere end sql-kommandoen, hvilket fører til uventede konsekvenser.

Udskudte begrænsninger: hvorfor de er nødvendige, og hvordan de fungerer

Lidt teori om udskudte begrænsninger.
Overvej et simpelt eksempel: Vi har en biloversigtstabel med to attributter - navnet og rækkefølgen på bilen i biblioteket.
Postgres: bloat, pg_repack og deferred constraints

create table cars
(
  name text constraint pk_cars primary key,
  ord integer not null constraint uk_cars unique
);



Antag, at vi var nødt til at bytte den første og den anden bil nogle steder. Den direkte løsning er at opdatere den første værdi til den anden og den anden til den første:

begin;
  update cars set ord = 2 where name = 'audi';
  update cars set ord = 1 where name = 'bmw';
commit;

Men når vi kører denne kode, forventes vi at få en begrænsningsovertrædelse, fordi rækkefølgen af ​​værdierne i tabellen er unik:

[23305] ERROR: duplicate key value violates unique constraint “uk_cars”
Detail: Key (ord)=(2) already exists.

Hvordan gør man det anderledes? Mulighed 1: Tilføj en ekstra erstatning af værdien med en ordre, der med garanti ikke eksisterer i tabellen, for eksempel "-XNUMX". I programmering kaldes dette "udveksling af værdier af to variabler med en tredje." Den eneste ulempe ved denne metode er den ekstra opdatering.

Mulighed to: Redesign tabellen til at bruge en flydende kommadatatype for eksponentværdien i stedet for heltal. Når du derefter opdaterer værdien fra for eksempel 1 til 2.5, vil den første post automatisk "stå" mellem den anden og tredje. Denne løsning virker, men der er to begrænsninger. For det første virker det ikke for dig, hvis værdien bruges et sted i grænsefladen. For det andet, afhængigt af præcisionen af ​​datatypen, vil du have et begrænset antal mulige indsættelser, før du genberegner værdierne for alle poster.

Mulighed tre: gør begrænsningen udskudt, så den kun kontrolleres på tidspunktet for forpligtelsen:

create table cars
(
  name text constraint pk_cars primary key,
  ord integer not null constraint uk_cars unique deferrable initially deferred
);

Da logikken i vores første anmodning sikrer, at alle værdier er unikke på det tidspunkt, hvor forpligtelsen er foretaget, vil forpligtelsen lykkes.

Eksemplet diskuteret ovenfor er selvfølgelig meget syntetisk, men det afslører ideen. I vores applikation bruger vi udskudte begrænsninger til at implementere den logik, der er ansvarlig for at løse konflikter, når brugere interagerer med delte widgetobjekter på tavlen på samme tid. Brugen af ​​sådanne begrænsninger giver os mulighed for at gøre applikationskoden lidt enklere.

Generelt, afhængigt af begrænsningstypen i Postgres, er der tre niveauer af granularitet af deres validering: række, transaktion og udtryk.
Postgres: bloat, pg_repack og deferred constraints
Kilde: begriffs

CHECK og NOT NULL er altid afkrydset på rækkeniveau, for andre restriktioner, som det kan ses af tabellen, er der forskellige muligheder. Du kan læse mere her.

For at opsummere kort, fører udskudte begrænsninger i en række situationer til mere læsbar kode og færre kommandoer. Du skal dog betale for dette ved at komplicere fejlretningsprocessen, da det øjeblik, hvor fejlen opstår, og det øjeblik, du lærer om det, er adskilt i tid. Et andet muligt problem er, at planlæggeren muligvis ikke altid er i stand til at opbygge en optimal plan, hvis en forsinket begrænsning er involveret i forespørgslen.

Forbedring af pg_repack

Vi har dækket, hvad udskudte begrænsninger er, men hvordan hænger de sammen med vores problem? Husk den fejl, vi fik tidligere:

$ ./pg_repack -t tablename -o id
INFO: repacking table "tablename"
ERROR: query failed: 
    ERROR: duplicate key value violates unique constraint "index_16508"
DETAIL:  Key (id, index)=(100500, 42) already exists.

Det opstår, når data kopieres fra logtabellen til en ny tabel. Det ser mærkeligt ud, fordi dataene i logtabellen er forpligtet sammen med dataene i den originale tabel. Hvis de opfylder den oprindelige tabels begrænsninger, hvordan kan de så overtræde de samme begrænsninger i den nye?

Som det viste sig, ligger roden til problemet i det forrige trin af pg_repack, som kun opretter indekser, men ikke begrænsninger: den gamle tabel havde en unik begrænsning, og den nye skabte i stedet et unikt indeks.

Postgres: bloat, pg_repack og deferred constraints

Det er vigtigt at bemærke her, at hvis begrænsningen er normal og ikke udskudt, så svarer det unikke indeks, der oprettes i stedet for det, til denne begrænsning, fordi unikke begrænsninger i Postgres implementeres ved at skabe et unikt indeks. Men i tilfælde af en forsinket begrænsning er adfærden ikke den samme, fordi indekset ikke kan udskydes og kontrolleres altid på det tidspunkt, hvor sql-kommandoen udføres.

Essensen af ​​problemet ligger således i den "udsatte" kontrol: i den originale tabel forekommer den på tidspunktet for commit, og i den nye på tidspunktet for udførelsen af ​​sql-kommandoen. Så vi skal sikre os, at kontrollen udføres på samme måde i begge tilfælde: enten altid forsinket eller altid med det samme.

Så hvilke ideer havde vi.

Opret indeks svarende til udskudt

Den første idé er at udføre begge kontroller i øjeblikkelig tilstand. Dette kan give anledning til flere falske positiver ved begrænsningen, men hvis der er få af dem, bør dette ikke påvirke brugernes arbejde, da sådanne konflikter er en normal situation for dem. De opstår for eksempel, når to brugere begynder at redigere den samme widget på samme tid, og klienten for den anden bruger ikke har tid til at modtage information om, at widgeten allerede er blokeret for redigering af den første bruger. I en sådan situation svarer serveren til den anden bruger med et afslag, og dens klient ruller ændringerne tilbage og låser widgetten. Lidt senere, når den første bruger er færdig med at redigere, vil den anden modtage information om, at widgetten ikke længere er blokeret, og vil være i stand til at gentage sin handling.

Postgres: bloat, pg_repack og deferred constraints

For at sikre, at checks altid er i uudskudt tilstand, har vi oprettet et nyt indeks svarende til den oprindelige udskudte begrænsning:

CREATE UNIQUE INDEX CONCURRENTLY uk_tablename__immediate ON tablename (id, index);
-- run pg_repack
DROP INDEX CONCURRENTLY uk_tablename__immediate;

På testmiljøet modtog vi kun få forventede fejl. Succes! Vi kørte pg_repack igen på prod og fik 5 fejl på den første klynge på en times arbejde. Dette er et acceptabelt resultat. Men allerede på den anden klynge steg antallet af fejl markant, og vi måtte stoppe pg_repack.

Hvorfor skete det? Sandsynligheden for, at der opstår en fejl, afhænger af, hvor mange brugere der arbejder samtidigt med de samme widgets. Tilsyneladende var der i det øjeblik meget færre konkurrencemæssige ændringer med de data, der var gemt på den første klynge, end på resten, dvs. vi er bare "heldige".

Ideen virkede ikke. I det øjeblik så vi to andre løsninger: omskriv vores applikationskode for at opgive udskudte begrænsninger, eller "lær" pg_repack at arbejde med dem. Vi valgte den anden.

Erstat indekser i ny tabel med udskudte begrænsninger fra den oprindelige tabel

Formålet med revisionen var indlysende - hvis den oprindelige tabel har en udskudt begrænsning, så er det for den nye nødvendigt at oprette en sådan begrænsning og ikke et indeks.

For at teste vores ændringer skrev vi en simpel test:

  • tabel med udskudt begrænsning og én post;
  • vi indsætter data i løkken, der er i konflikt med den eksisterende post;
  • lav en opdatering - dataene er ikke længere i konflikt;
  • begå ændringer.

create table test_table
(
  id serial,
  val int,
  constraint uk_test_table__val unique (val) deferrable initially deferred 
);

INSERT INTO test_table (val) VALUES (0);
FOR i IN 1..10000 LOOP
  BEGIN
    INSERT INTO test_table VALUES (0) RETURNING id INTO v_id;
    UPDATE test_table set val = i where id = v_id;
    COMMIT;
  END;
END LOOP;

Den originale version af pg_repack gik altid ned ved den første indsættelse, den ændrede version fungerede uden fejl. Store.

Vi går til prod og igen får vi en fejl i samme fase af kopiering af data fra logtabellen til en ny:

$ ./pg_repack -t tablename -o id
INFO: repacking table "tablename"
ERROR: query failed: 
    ERROR: duplicate key value violates unique constraint "index_16508"
DETAIL:  Key (id, index)=(100500, 42) already exists.

En klassisk situation: alt fungerer på testmiljøer, men ikke på produktion?!

APPLY_COUNT og krydset mellem to batcher

Vi begyndte at analysere koden bogstaveligt talt linje for linje og opdagede et vigtigt punkt: data overføres fra logtabellen til den nye i batches, APPLY_COUNT konstanten indikerede batchens størrelse:

for (;;)
{
num = apply_log(connection, table, APPLY_COUNT);

if (num > MIN_TUPLES_BEFORE_SWITCH)
     continue;  /* there might be still some tuples, repeat. */
...
}

Problemet er, at dataene fra den oprindelige transaktion, hvor flere operationer potentielt kan overtræde begrænsningen, kan ende i krydset mellem to batches under overførslen - halvdelen af ​​kommandoerne vil blive begået i den første batch, og den anden halvdel i den anden. Og her, hvor heldigt: Hvis holdene i den første batch ikke overtræder noget, så er alt fint, men hvis de gør det, opstår der en fejl.

APPLY_COUNT er lig med 1000 poster, hvilket forklarer, hvorfor vores test var vellykket - de dækkede ikke "batch junction"-tilfældet. Vi brugte to kommandoer - indsæt og opdater, så præcis 500 transaktioner af to kommandoer blev altid placeret i en batch, og vi oplevede ikke problemer. Efter at have tilføjet den anden opdatering, holdt vores redigering op med at virke:

FOR i IN 1..10000 LOOP
  BEGIN
    INSERT INTO test_table VALUES (1) RETURNING id INTO v_id;
    UPDATE test_table set val = i where id = v_id;
    UPDATE test_table set val = i where id = v_id; -- one more update
    COMMIT;
  END;
END LOOP;

Så den næste opgave er at sikre, at dataene fra den oprindelige tabel, der blev ændret i en transaktion, også kommer ind i den nye tabel inden for en transaktion.

Afvisning af batching

Og vi havde igen to løsninger. For det første: Lad os nægte at opdele i batches helt og gøre dataoverførslen til en enkelt transaktion. Til fordel for denne beslutning var dens enkelhed - de nødvendige kodeændringer er minimale (i øvrigt i ældre versioner dengang fungerede pg_reorg på den måde). Men der er et problem - vi skaber en langsigtet transaktion, og dette er, som tidligere nævnt, en trussel mod fremkomsten af ​​en ny bloat.

Den anden løsning er mere kompliceret, men sandsynligvis mere korrekt: opret en kolonne i logtabellen med identifikatoren for den transaktion, der tilføjede data til tabellen. Når vi kopierer data, kan vi gruppere dem efter denne attribut og sikre, at relaterede ændringer overføres sammen. Batchen vil blive dannet af flere transaktioner (eller en stor) og dens størrelse vil variere afhængigt af, hvor meget data der er blevet ændret i disse transaktioner. Det er vigtigt at bemærke, at da data for forskellige transaktioner kommer ind i logtabellen i tilfældig rækkefølge, vil det ikke længere være muligt at læse dem sekventielt, som det var før. seqscan på hver anmodning filtreret af tx_id er for dyrt, du har brug for et indeks, men det vil også sænke metoden på grund af omkostningerne ved at opdatere det. Generelt er du som altid nødt til at ofre noget.

Så vi besluttede at starte med den første mulighed, som en enklere. Først var det nødvendigt at forstå, om en lang transaktion ville være et reelt problem. Da hovedoverførslen af ​​data fra den gamle tabel til den nye også sker i en lang transaktion, er spørgsmålet blevet transformeret til "hvor meget vil vi øge denne transaktion?" Varigheden af ​​den første transaktion afhænger hovedsageligt af bordets størrelse. Varigheden af ​​den nye afhænger af, hvor mange ændringer der vil akkumulere i tabellen under dataoverførslen, dvs. på belastningens intensitet. Kørslen pg_repack fandt sted på et tidspunkt med minimal servicebelastning, og mængden af ​​ændringer var uforlignelig lille sammenlignet med den oprindelige tabelstørrelse. Vi besluttede, at vi kan forsømme tidspunktet for en ny transaktion (til sammenligning er gennemsnittet 1 time og 2-3 minutter).

Forsøgene var positive. Lancering på udsalg også. For klarhedens skyld er her et billede med størrelsen af ​​en af ​​baserne efter løbet:

Postgres: bloat, pg_repack og deferred constraints

Da denne løsning helt passede til os, forsøgte vi ikke at implementere den anden, men vi overvejer muligheden for at diskutere det med udviklerne af udvidelsen. Vores nuværende revision er desværre endnu ikke klar til udgivelse, da vi kun løste problemet med unikke forsinkede begrænsninger, og for en fuldgyldig patch skal der laves support til andre typer. Det håber vi at kunne gøre i fremtiden.

Måske har du et spørgsmål, hvorfor vi overhovedet blev involveret i denne historie med forfining af pg_repack, og brugte for eksempel ikke dens analoger? På et tidspunkt tænkte vi også over det, men den positive oplevelse af at bruge det tidligere, på borde uden forsinkede begrænsninger, motiverede os til at prøve at forstå essensen af ​​problemet og løse det. Derudover kræver det at bruge andre løsninger også tid til at udføre test, så vi besluttede, at vi først ville prøve at løse problemet i det, og hvis vi indså, at vi ikke kunne gøre det inden for rimelig tid, så ville vi begynde at overveje analoger.

Fund

Hvad vi kan anbefale baseret på vores egne erfaringer:

  1. Overvåg din oppustethed. Baseret på overvågningsdataene vil du være i stand til at forstå, hvor godt autovakuum er tunet.
  2. Indstil AUTOVACUUM for at holde oppustethed på et acceptabelt niveau.
  3. Hvis oppustet stadig vokser, og du ikke kan håndtere det med out-of-the-box værktøjer, skal du ikke være bange for at bruge eksterne udvidelser. Det vigtigste er at teste alt godt.
  4. Vær ikke bange for at ændre eksterne løsninger, så de passer til dine behov – nogle gange kan det være mere effektivt og endda nemmere end at ændre din egen kode.

Kilde: www.habr.com

Tilføj en kommentar