Postgres: bloat, pg_repack i odgođena ograničenja

Postgres: bloat, pg_repack i odgođena ograničenja

Učinak bloata na tablice i indekse nadaleko je poznat i prisutan je ne samo u Postgresu. Postoje načini za rješavanje toga izvan okvira, poput VACUUM FULL ili CLUSTER, ali oni zaključavaju stolove tijekom rada i stoga se ne mogu uvijek koristiti.

Članak će sadržavati malo teorije o tome kako dolazi do nadutosti, kako se možete boriti protiv nje, o odgođenim ograničenjima i problemima koje ona donose pri korištenju proširenja pg_repack.

Ovaj je članak napisan na temelju moj govor na PgConf.Rusija 2020.

Zašto dolazi do nadutosti?

Postgres se temelji na modelu s više verzija (MVCC). Njegova bit je da svaki red u tablici može imati nekoliko verzija, dok transakcije ne vide više od jedne od tih verzija, ali ne nužno iste. To omogućuje nekoliko transakcija da rade istovremeno i nemaju gotovo nikakav utjecaj jedna na drugu.

Očito, sve te verzije moraju biti pohranjene. Postgres radi s memorijom stranicu po stranicu, a stranica je minimalna količina podataka koja se može pročitati s diska ili napisati. Pogledajmo mali primjer da bismo razumjeli kako se to događa.

Recimo da imamo tablicu kojoj smo dodali nekoliko zapisa. Na prvoj stranici datoteke u kojoj je pohranjena tablica pojavili su se novi podaci. Ovo su žive verzije redaka koje su dostupne drugim transakcijama nakon predaje (radi jednostavnosti, pretpostavit ćemo da je razina izolacije Read Committed).

Postgres: bloat, pg_repack i odgođena ograničenja

Zatim smo ažurirali jedan od unosa, čime smo staru verziju označili kao nevažnu.

Postgres: bloat, pg_repack i odgođena ograničenja

Korak po korak, ažurirajući i brišući verzije redaka, došli smo do stranice na kojoj je otprilike polovica podataka “smeće”. Ovi podaci nisu vidljivi nijednoj transakciji.

Postgres: bloat, pg_repack i odgođena ograničenja

Postgres ima mehanizam VAKUUM, koji čisti zastarjele verzije i stvara mjesta za nove podatke. Ali ako nije dovoljno agresivno konfiguriran ili je zauzet radom u drugim tablicama, onda ostaju “podaci smeća” i moramo koristiti dodatne stranice za nove podatke.

Dakle, u našem primjeru, u nekom trenutku u vremenu tablica će se sastojati od četiri stranice, ali će samo polovica sadržavati žive podatke. Zbog toga ćemo prilikom pristupa tablici očitati puno više podataka nego što je potrebno.

Postgres: bloat, pg_repack i odgođena ograničenja

Čak i ako VACUUM sada izbriše sve nevažne verzije redaka, situacija se neće dramatično popraviti. Imat ćemo slobodnog prostora na stranicama ili čak cijelim stranicama za nove retke, ali ćemo i dalje čitati više podataka nego što je potrebno.
Usput, ako je potpuno prazna stranica (druga u našem primjeru) bila na kraju datoteke, tada bi je VACUUM mogao obrezati. Ali sada je ona u sredini, pa se s njom ništa ne može.

Postgres: bloat, pg_repack i odgođena ograničenja

Kada broj takvih praznih ili vrlo rijetkih stranica postane velik, što se naziva bloat, to počinje utjecati na performanse.

Sve gore opisano je mehanika nastanka bloata u tablicama. U indeksima se to događa otprilike na isti način.

Imam li nadutost?

Postoji nekoliko načina da utvrdite imate li nadutost. Ideja prvog je korištenje interne statistike Postgresa, koja sadrži približne informacije o broju redaka u tablicama, broju "živih" redaka itd. Na internetu možete pronaći mnoge varijacije gotovih skripti. Uzeli smo kao osnovu skripta od PostgreSQL stručnjaka, koji mogu procijeniti bloat tablice zajedno s toast i bloat btree indeksima. Prema našem iskustvu, njegova pogreška je 10-20%.

Drugi način je korištenje ekstenzije pgstattuple, što vam omogućuje da pogledate unutar stranica i dobijete procijenjenu i točnu vrijednost povećanja. Ali u drugom slučaju, morat ćete skenirati cijelu tablicu.

Malu vrijednost bloata, do 20%, smatramo prihvatljivom. Može se smatrati analogom faktora punjenja za tabeliranje и indeksi. Na 50% i više mogu početi problemi s performansama.

Načini borbe protiv nadutosti

Postgres ima nekoliko načina za rješavanje nadutosti odmah po izlasku, ali oni nisu uvijek prikladni za sve.

Konfigurirajte AUTOVAKUUM kako ne bi došlo do nadimanja. Točnije, držati ga na vama prihvatljivoj razini. Ovo izgleda kao "kapetanov" savjet, ali u stvarnosti to nije uvijek lako postići. Na primjer, imate aktivan razvoj s redovitim promjenama podatkovne sheme ili je u tijeku neka vrsta migracije podataka. Kao rezultat toga, vaš profil opterećenja može se često mijenjati i obično će varirati od stola do stola. To znači da morate stalno raditi malo unaprijed i prilagoditi AUTOVAKUUM promjenjivom profilu svakog stola. Ali očito to nije lako učiniti.

Još jedan uobičajeni razlog zašto AUTOVACUUM ne može držati korak s tablicama je taj što postoje dugotrajne transakcije koje ga sprječavaju u čišćenju podataka koji su dostupni tim transakcijama. Preporuka je i ovdje očigledna - riješite se "visećih" transakcija i minimizirajte vrijeme aktivnih transakcija. Ali ako je opterećenje vaše aplikacije hibrid OLAP-a i OLTP-a, tada možete istovremeno imati mnogo čestih ažuriranja i kratkih upita, kao i dugotrajne operacije - na primjer, izradu izvješća. U takvoj situaciji vrijedi razmisliti o raspodjeli opterećenja na različite baze, što će omogućiti finije podešavanje svake od njih.

Još jedan primjer - čak i ako je profil homogen, ali je baza podataka pod vrlo velikim opterećenjem, tada se čak ni najagresivniji AUTOVACUUM možda neće nositi i doći će do nadimanja. Skaliranje (okomito ili vodoravno) je jedino rješenje.

Što učiniti u situaciji kada ste postavili AUTOVAKUUM, ali nadutost i dalje raste.

Momčad VAKUUM PUN obnavlja sadržaj tablica i indeksa i ostavlja samo relevantne podatke u njima. Kako bi se eliminirao bloat, radi savršeno, ali tijekom njegovog izvođenja hvata se ekskluzivno zaključavanje tablice (AccessExclusiveLock), koje neće dopustiti izvršavanje upita na ovoj tablici, čak ni odabire. Ako si možete priuštiti zaustavljanje svoje usluge ili njenog dijela na neko vrijeme (od nekoliko desetaka minuta do nekoliko sati, ovisno o veličini baze podataka i vašem hardveru), onda je ova opcija najbolja. Nažalost, nemamo vremena pokrenuti VACUUM FULL tijekom planiranog održavanja, pa nam ova metoda nije prikladna.

Momčad CLUSTER Ponovno gradi sadržaj tablica na isti način kao i VACUUM FULL, ali vam omogućuje da navedete indeks prema kojem će podaci biti fizički poredani na disku (ali ubuduće redoslijed nije zajamčen za nove retke). U određenim situacijama ovo je dobra optimizacija za brojne upite - s čitanjem više zapisa po indeksu. Nedostatak naredbe je isti kao i kod VACUUM FULL - zaključava stol tijekom rada.

Momčad REINDEX sličan prethodna dva, ali ponovno gradi određeni indeks ili sve indekse tablice. Zaključavanja su nešto slabija: ShareLock na tablici (sprečava izmjene, ali dopušta odabir) i AccessExclusiveLock na indeksu koji se ponovno gradi (blokira upite koji koriste ovaj indeks). Međutim, u 12. verziji Postgresa pojavio se parametar ISTOVREMENO, koji vam omogućuje ponovnu izgradnju indeksa bez blokiranja istovremenog dodavanja, mijenjanja ili brisanja zapisa.

U ranijim verzijama Postgresa, možete postići rezultat sličan REINDEX COCURRENTLY koristeći KREIRAJ INDEKS ISTODOBNO. Omogućuje vam stvaranje indeksa bez strogog zaključavanja (ShareUpdateExclusiveLock, koji ne ometa paralelne upite), zatim zamijenite stari indeks novim i izbrišite stari indeks. To vam omogućuje da uklonite napuhanost indeksa bez ometanja vaše aplikacije. Važno je uzeti u obzir da će prilikom ponovne izgradnje indeksa doći do dodatnog opterećenja diskovnog podsustava.

Dakle, ako za indekse postoje načini za uklanjanje napuhanosti "u hodu", onda ne postoje za tablice. Ovdje na scenu stupaju razna vanjska proširenja: pg_repack (bivši pg_reorg), pgcompact, pgcompacttable i drugi. U ovom članku ih neću uspoređivati ​​i govorit ću samo o pg_repacku koji, nakon nekih izmjena, i sami koristimo.

Kako radi pg_repack

Postgres: bloat, pg_repack i odgođena ograničenja
Recimo, imamo sasvim običnu tablicu – s indeksima, ograničenjima i, nažalost, s bloatom. Prvi korak pg_repacka je stvaranje tablice dnevnika za pohranjivanje podataka o svim promjenama dok se izvodi. Okidač će replicirati ove promjene za svako umetanje, ažuriranje i brisanje. Zatim se kreira tablica, po strukturi slična izvornoj, ali bez indeksa i ograničenja, kako se ne bi usporavao proces umetanja podataka.

Zatim, pg_repack prenosi podatke iz stare tablice u novu tablicu, automatski filtrira sve nebitne retke, a zatim stvara indekse za novu tablicu. Tijekom izvođenja svih ovih operacija, promjene se akumuliraju u tablici dnevnika.

Sljedeći korak je prijenos promjena u novu tablicu. Migracija se izvodi kroz nekoliko iteracija, a kada u tablici dnevnika ostane manje od 20 unosa, pg_repack dobiva jaku bravu, migrira najnovije podatke i zamjenjuje staru tablicu novom u tablicama sustava Postgres. Ovo je jedino i vrlo kratko vrijeme kada nećete moći raditi sa stolom. Nakon toga brišu se stara tablica i tablica sa zapisima i oslobađa se prostor u datotečnom sustavu. Proces je završen.

U teoriji sve izgleda super, ali što se događa u praksi? Testirali smo pg_repack bez opterećenja i pod opterećenjem te provjerili njegov rad u slučaju prijevremenog zaustavljanja (drugim riječima, korištenjem Ctrl+C). Svi testovi su bili pozitivni.

Otišli smo u trgovinu - i onda nije sve išlo kako smo očekivali.

Prva palačinka u prodaji

Na prvom klasteru primili smo pogrešku o kršenju jedinstvenog ograničenja:

$ ./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.

Ovo ograničenje je imalo automatski generirani naziv index_16508 - stvorio ga je pg_repack. Na temelju atributa uključenih u njegov sastav odredili smo „naše“ ograničenje koje mu odgovara. Problem se pokazao u tome što se ne radi o sasvim običnom ograničenju, već o odgođenom (odgođeno ograničenje), tj. njegova se provjera izvodi kasnije od sql naredbe, što dovodi do neočekivanih posljedica.

Odgođena ograničenja: zašto su potrebna i kako djeluju

Malo teorije o odgođenim ograničenjima.
Razmotrimo jednostavan primjer: imamo tablicu-priručnik automobila s dva atributa - imenom i redoslijedom automobila u imeniku.
Postgres: bloat, pg_repack i odgođena ograničenja

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



Recimo da smo trebali zamijeniti prvi i drugi automobil. Jednostavno rješenje je ažurirati prvu vrijednost na drugu, a drugu na prvu:

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

Ali kada pokrenemo ovaj kod, očekujemo kršenje ograničenja jer je redoslijed vrijednosti u tablici jedinstven:

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

Kako to mogu učiniti drugačije? Prva opcija: dodajte dodatnu zamjenu vrijednosti narudžbi koja zajamčeno ne postoji u tablici, na primjer “-1”. U programiranju se to zove "razmjena vrijednosti dviju varijabli kroz treću." Jedini nedostatak ove metode je dodatno ažuriranje.

Druga opcija: redizajnirajte tablicu tako da za vrijednost narudžbe koristi tip podataka s pomičnim zarezom umjesto cijelih brojeva. Zatim, prilikom ažuriranja vrijednosti s 1, na primjer, na 2.5, prvi će unos automatski "stati" između drugog i trećeg. Ovo rješenje funkcionira, ali postoje dva ograničenja. Prvo, neće raditi ako se vrijednost koristi negdje u sučelju. Drugo, ovisno o preciznosti tipa podataka, imat ćete ograničen broj mogućih umetanja prije ponovnog izračuna vrijednosti svih zapisa.

Opcija tri: učinite ograničenje odgođenim tako da se provjerava samo u vrijeme predaje:

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

Budući da logika našeg početnog zahtjeva osigurava da su sve vrijednosti jedinstvene u trenutku predaje, on će uspjeti.

Gore razmotren primjer je, naravno, vrlo sintetičan, ali otkriva ideju. U našoj aplikaciji koristimo odgođena ograničenja za implementaciju logike koja je odgovorna za rješavanje sukoba kada korisnici istovremeno rade s zajedničkim widget objektima na ploči. Korištenje takvih ograničenja omogućuje nam da programski kod učinimo malo jednostavnijim.

Općenito, ovisno o vrsti ograničenja, Postgres ima tri razine granularnosti za njihovu provjeru: razine retka, transakcije i razine izraza.
Postgres: bloat, pg_repack i odgođena ograničenja
Izvor: prosjaci

CHECK i NOT NULL uvijek su označeni na razini reda; za ostala ograničenja, kao što se može vidjeti iz tablice, postoje različite opcije. Možete pročitati više здесь.

Da ukratko rezimiramo, odgođena ograničenja u brojnim situacijama daju čitljiviji kod i manje naredbi. Međutim, to morate platiti kompliciranjem procesa otklanjanja pogrešaka, budući da su trenutak nastanka greške i trenutak kada saznate za nju vremenski odvojeni. Drugi mogući problem je da planer možda neće uvijek moći konstruirati optimalan plan ako zahtjev uključuje odgođeno ograničenje.

Poboljšanje pg_repack

Pokrili smo što su odgođena ograničenja, ali kako se ona odnose na naš problem? Prisjetimo se greške koju smo ranije primili:

$ ./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.

To se događa kada se podaci kopiraju iz tablice dnevnika u novu tablicu. Ovo izgleda čudno jer... podaci u tablici dnevnika predaju se zajedno s podacima u izvornoj tablici. Ako zadovoljavaju ograničenja izvorne tablice, kako mogu prekršiti ista ograničenja u novoj?

Kako se pokazalo, korijen problema leži u prethodnom koraku pg_repacka, koji stvara samo indekse, ali ne i ograničenja: stara tablica je imala jedinstveno ograničenje, a nova je umjesto toga stvorila jedinstveni indeks.

Postgres: bloat, pg_repack i odgođena ograničenja

Ovdje je važno napomenuti da ako je ograničenje normalno i nije odgođeno, tada je stvoreni jedinstveni indeks ekvivalentan ovom ograničenju, jer Jedinstvena ograničenja u Postgresu implementirana su stvaranjem jedinstvenog indeksa. Ali u slučaju odgođenog ograničenja, ponašanje nije isto, jer se indeks ne može odgoditi i uvijek se provjerava u trenutku izvršavanja sql naredbe.

Dakle, bit problema leži u “kašnjenju” provjere: u originalnoj tablici to se događa u trenutku komitiranja, au novoj tablici u trenutku izvršavanja sql naredbe. To znači da moramo biti sigurni da se provjere izvode na isti način u oba slučaja: ili uvijek s odgodom ili uvijek odmah.

Pa kakve smo ideje imali?

Stvorite indeks sličan odgođenom

Prva ideja je izvršiti obje provjere u trenutnom načinu rada. To može generirati nekoliko lažno pozitivnih ograničenja, ali ako ih je malo, to ne bi trebalo utjecati na rad korisnika, budući da su takvi sukobi za njih normalna situacija. Do njih dolazi, primjerice, kada dva korisnika počnu uređivati ​​isti widget u isto vrijeme, a klijent drugog korisnika ne stigne primiti informaciju da je widget već blokiran za uređivanje od strane prvog korisnika. U takvoj situaciji poslužitelj odbija drugog korisnika, a njegov klijent vraća promjene i blokira widget. Nešto kasnije, kada prvi korisnik završi uređivanje, drugi će dobiti informaciju da widget više nije blokiran i moći će ponoviti svoju radnju.

Postgres: bloat, pg_repack i odgođena ograničenja

Kako bismo osigurali da su provjere uvijek u neodgođenom načinu rada, stvorili smo novi indeks sličan izvornom odgođenom ograničenju:

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

U testnom okruženju primili smo samo nekoliko očekivanih pogrešaka. Uspjeh! Ponovno smo pokrenuli pg_repack na produkciji i dobili 5 grešaka na prvom klasteru u sat vremena rada. Ovo je prihvatljiv rezultat. Međutim, već na drugom klasteru broj grešaka se značajno povećao i morali smo zaustaviti pg_repack.

Zašto se to dogodilo? Vjerojatnost pojave pogreške ovisi o tome koliko korisnika radi s istim widgetima u isto vrijeme. Očigledno je u tom trenutku bilo puno manje konkurentskih promjena s podacima pohranjenim na prvom klasteru nego na ostalima, tj. samo smo imali "sreće".

Ideja nije uspjela. U tom smo trenutku vidjeli dva druga rješenja: prepisati naš aplikacijski kod kako bismo se oslobodili odgođenih ograničenja ili "naučiti" pg_repack da radi s njima. Izabrali smo ovo drugo.

Zamijenite indekse u novoj tablici s odgođenim ograničenjima iz izvorne tablice

Svrha revizije bila je očita - ako izvorna tablica ima odgođeno ograničenje, tada za novu trebate stvoriti takvo ograničenje, a ne indeks.

Kako bismo testirali naše promjene, napisali smo jednostavan test:

  • tablica s odgođenim ograničenjem i jednim zapisom;
  • umetnuti podatke u petlju koja je u sukobu s postojećim zapisom;
  • napravite ažuriranje – podaci više nisu u sukobu;
  • izvrši promjene.

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;

Originalna verzija pg_repacka uvijek se srušila pri prvom umetanju, modificirana verzija je radila bez grešaka. Sjajno.

Idemo u proizvodnju i ponovno dobivamo pogrešku u istoj fazi kopiranja podataka iz tablice dnevnika u novu:

$ ./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.

Klasična situacija: u testnim okruženjima sve radi, ali u produkciji ne?!

APPLY_COUNT i spoj dviju serija

Počeli smo analizirati kod doslovno redak po redak i otkrili važnu točku: podaci se prenose iz tablice dnevnika u novu u serijama, konstanta APPLY_COUNT označavala je veličinu serije:

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

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

Problem je u tome što podaci iz originalne transakcije, u kojoj bi nekoliko operacija potencijalno moglo prekršiti ograničenje, kada se prenesu, mogu završiti na spoju dviju serija - polovica naredbi bit će predana u prvoj seriji, a druga polovica u drugom. I ovdje, ovisno o vašoj sreći: ako timovi ništa ne prekrše u prvoj seriji, onda je sve u redu, ali ako jesu, dolazi do pogreške.

APPLY_COUNT jednako je 1000 zapisa, što objašnjava zašto su naši testovi bili uspješni - nisu pokrili slučaj "batch junction". Koristili smo dvije naredbe - insert i update, tako da je točno 500 transakcija dvije naredbe uvijek stavljeno u batch i nismo imali nikakvih problema. Nakon dodavanja drugog ažuriranja, naše uređivanje je prestalo raditi:

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;

Dakle, sljedeći zadatak je pobrinuti se da podaci iz originalne tablice, koja je promijenjena u jednoj transakciji, završe u novoj tablici također unutar jedne transakcije.

Odbijanje šarže

I opet smo imali dva rješenja. Prvo: potpuno napustimo particioniranje u pakete i prenesimo podatke u jednoj transakciji. Prednost ovog rješenja bila je njegova jednostavnost - potrebne izmjene koda bile su minimalne (usput, u starijim verzijama pg_reorg je radio upravo tako). Ali postoji problem - stvaramo dugotrajnu transakciju, a to je, kao što je prethodno rečeno, prijetnja nastanku novog nadimanja.

Drugo rješenje je složenije, ali vjerojatno ispravnije: kreirajte stupac u tablici dnevnika s identifikatorom transakcije koja je dodala podatke u tablicu. Zatim, kada kopiramo podatke, možemo ih grupirati prema ovom atributu i osigurati da se povezane promjene prenose zajedno. Skupina će se formirati od nekoliko transakcija (ili jedne velike), a veličina će varirati ovisno o tome koliko je podataka promijenjeno u tim transakcijama. Važno je napomenuti da budući da podaci iz različitih transakcija ulaze u tablicu dnevnika nasumičnim redoslijedom, više ih neće biti moguće čitati sekvencijalno, kao što je to bilo prije. seqscan za svaki zahtjev s filtriranjem prema tx_id je preskup, potreban je indeks, ali će također usporiti metodu zbog troškova ažuriranja. Općenito, kao i uvijek, morate nešto žrtvovati.

Stoga smo odlučili započeti s prvom opcijom, jer je jednostavnija. Prvo je bilo potrebno razumjeti hoće li duga transakcija biti pravi problem. Budući da se glavni prijenos podataka iz stare tablice u novu također događa u jednoj dugoj transakciji, pitanje se transformiralo u "koliko ćemo povećati ovu transakciju?" Trajanje prve transakcije uglavnom ovisi o veličini stola. Trajanje novog ovisi o tome koliko se promjena nakupi u tablici tijekom prijenosa podataka, tj. na intenzitet opterećenja. Pokretanje pg_repack dogodilo se tijekom vremena minimalnog opterećenja servisa, a količina promjena bila je neproporcionalno mala u usporedbi s izvornom veličinom tablice. Odlučili smo da možemo zanemariti vrijeme nove transakcije (usporedbe radi, u prosjeku je to 1 sat i 2-3 minute).

Pokusi su bili pozitivni. Pokrenite i proizvodnju. Radi jasnoće, ovdje je slika s veličinom jedne od baza podataka nakon pokretanja:

Postgres: bloat, pg_repack i odgođena ograničenja

Budući da smo bili u potpunosti zadovoljni ovim rješenjem, nismo pokušali implementirati drugo, ali razmatramo mogućnost razgovora s programerima proširenja. Naša trenutna revizija, nažalost, još nije spremna za objavljivanje, budući da smo samo riješili problem s jedinstvenim odgođenim ograničenjima, a za potpunu zakrpu potrebno je osigurati podršku za druge vrste. Nadamo se da ćemo to moći učiniti u budućnosti.

Možda imate pitanje zašto smo se uopće uključili u ovu priču s modifikacijom pg_repacka, a nismo, na primjer, koristili njegove analoge? U nekom trenutku smo i mi razmišljali o tome, ali pozitivno iskustvo ranijeg korištenja, na tablicama bez odgođenih ograničenja, motiviralo nas je da pokušamo shvatiti bit problema i riješiti ga. Osim toga, korištenje drugih rješenja također zahtijeva vrijeme za provođenje testova, pa smo odlučili da ćemo prvo pokušati riješiti problem u njemu, a ako shvatimo da to ne možemo učiniti u razumnom roku, tada ćemo početi tražiti analoge .

Zaključci

Što možemo preporučiti na temelju vlastitog iskustva:

  1. Pratite svoju nadutost. Na temelju podataka praćenja možete shvatiti koliko je dobro konfiguriran automatski usisivač.
  2. Podesite AUTOVAKUUM kako biste zadržali nadutost na prihvatljivoj razini.
  3. Ako nadutost i dalje raste i ne možete je prevladati pomoću gotovih alata, nemojte se bojati koristiti vanjske ekstenzije. Glavno je sve dobro testirati.
  4. Nemojte se bojati modificirati vanjska rješenja kako bi odgovarala vašim potrebama - ponekad to može biti učinkovitije i čak lakše od mijenjanja vlastitog koda.

Izvor: www.habr.com

Dodajte komentar