Postgres: bloat, pg_repack ja edasilükatud piirangud

Postgres: bloat, pg_repack ja edasilükatud piirangud

Kõhupuhituse mõju tabelitele ja indeksitele on laialt teada ja see ei esine mitte ainult Postgresis. Sellega toimetulemiseks on olemas viise, näiteks VACUUM FULL või CLUSTER, kuid need lukustavad töö ajal lauad ja seetõttu ei saa neid alati kasutada.

Artikkel sisaldab väikest teooriat selle kohta, kuidas puhitus tekib, kuidas sellega võidelda, edasilükatud piirangute ja probleemide kohta, mida need põhjustavad laienduse pg_repack kasutamisel.

See artikkel on kirjutatud selle põhjal minu kõne PgConf.Russia 2020. aastal.

Miks tekib puhitus?

Postgres põhineb mitme versiooni mudelil (MVCC). Selle olemus seisneb selles, et igal tabelireal võib olla mitu versiooni, samas kui tehingud ei näe neist rohkem kui ühte, kuid mitte tingimata sama versiooni. See võimaldab mitmel tehingul samaaegselt toimida ja praktiliselt ei mõjuta üksteist.

Ilmselgelt tuleb kõik need versioonid salvestada. Postgres töötab mäluga lehekülgede kaupa ja leht on minimaalne andmemaht, mida saab kettalt lugeda või kirjutada. Vaatame väikest näidet, et mõista, kuidas see juhtub.

Oletame, et meil on tabel, kuhu oleme lisanud mitu kirjet. Uued andmed on ilmunud faili esimesele lehele, kus tabel on salvestatud. Need on ridade reaalajas versioonid, mis on muude tehingute jaoks pärast kinnistamist saadaval (lihtsuse huvides eeldame, et eraldatuse tase on Read Committed).

Postgres: bloat, pg_repack ja edasilükatud piirangud

Seejärel värskendasime ühte kirjet, märkides sellega vana versiooni enam ebaoluliseks.

Postgres: bloat, pg_repack ja edasilükatud piirangud

Samm-sammult, uuendades ja kustutades reaversioone, jõudsime leheni, kus ligikaudu pool andmetest on “prügi”. Need andmed pole ühelegi tehingule nähtavad.

Postgres: bloat, pg_repack ja edasilükatud piirangud

Postgresil on mehhanism VAKUUM, mis puhastab vananenud versioonid ja teeb ruumi uutele andmetele. Aga kui see pole piisavalt agressiivselt konfigureeritud või töötab teistes tabelites, siis jäävad "prügiandmed" alles ja uute andmete jaoks peame kasutama lisalehti.

Nii et meie näites koosneb tabel mingil ajahetkel neljast lehest, kuid ainult pool sellest sisaldab reaalajas andmeid. Selle tulemusena loeme tabelile ligi pääsedes palju rohkem andmeid kui vaja.

Postgres: bloat, pg_repack ja edasilükatud piirangud

Isegi kui VACUUM kustutab nüüd kõik ebaolulised reaversioonid, ei parane olukord dramaatiliselt. Meil jääb uute ridade jaoks vaba ruumi lehtedel või isegi tervetel lehtedel, kuid me loeme siiski rohkem andmeid kui vaja.
Muide, kui faili lõpus oleks täiesti tühi leht (teine ​​meie näites), saaks VACUUM seda kärpida. Aga nüüd on ta keskel, nii et temaga ei saa midagi teha.

Postgres: bloat, pg_repack ja edasilükatud piirangud

Kui selliste tühjade või väga hõredate lehtede arv muutub suureks, mida nimetatakse paisumiseks, hakkab see jõudlust mõjutama.

Kõik ülalkirjeldatu on tabelites puhituse esinemise mehhanism. Indeksites toimub see peaaegu samamoodi.

Kas mul on puhitus?

On mitmeid viise, kuidas määrata, kas teil on puhitus. Esimese idee on kasutada sisemist Postgresi statistikat, mis sisaldab ligikaudset teavet tabelite ridade, "reaalajas" ridade jne kohta. Internetist leiate palju valmisskriptide variatsioone. Võtsime aluseks stsenaarium PostgreSQL Expertsist, mis suudab hinnata bloat tabeleid koos toast- ja bloat btree indeksidega. Meie kogemuse järgi on selle viga 10-20%.

Teine võimalus on laienduse kasutamine pgstattuple, mis võimaldab vaadata lehtede sisse ja saada nii hinnangulist kui ka täpset puhitusväärtust. Kuid teisel juhul peate skannima kogu tabeli.

Peame vastuvõetavaks väikest puhitusväärtust, kuni 20%. Seda võib pidada täiteteguri analoogiks lauad и indeksid. 50% ja üle selle võivad alata jõudlusprobleemid.

Puhituse vastu võitlemise viisid

Postgresil on mitu võimalust karbist väljavõetud puhitustega toimetulemiseks, kuid need ei sobi alati kõigile.

Seadistage AUTOVACUUM nii, et puhitus ei tekiks. Või täpsemalt – hoida seda endale vastuvõetaval tasemel. See näib olevat "kapteni" nõuanne, kuid tegelikult pole seda alati lihtne saavutada. Näiteks on teil aktiivne arendus koos andmeskeemi regulaarsete muudatustega või toimub andmete migratsioon. Selle tulemusena võib teie koormusprofiil sageli muutuda ja on tavaliselt tabeliti erinev. See tähendab, et peate pidevalt veidi ette töötama ja kohandama AUTOVACUUM iga laua muutuva profiiliga. Kuid ilmselgelt pole seda lihtne teha.

Teine levinud põhjus, miks AUTOVACUUM ei saa tabelitega sammu pidada, on see, et on pikaajalisi tehinguid, mis takistavad tal nende tehingute jaoks saadaolevaid andmeid puhastamast. Siin on ka soovitus ilmselge - vabanege "rippuvatest" tehingutest ja minimeerige aktiivsete tehingute aeg. Kuid kui teie rakenduse koormus on OLAP-i ja OLTP-i hübriid, saate korraga teha palju sagedasi värskendusi ja lühikesi päringuid, aga ka pikaajalisi toiminguid - näiteks aruande koostamist. Sellises olukorras tasub mõelda koormuse hajutamisele erinevate aluste vahel, mis võimaldab igaüht neist rohkem timmida.

Veel üks näide - isegi kui profiil on homogeenne, kuid andmebaas on väga suure koormuse all, ei pruugi isegi kõige agressiivsem AUTOVACUUM hakkama saada ja tekib paistetus. Ainus lahendus on skaleerimine (vertikaalne või horisontaalne).

Mida teha olukorras, kus oled AUTOVAKUUMI paika pannud, aga puhitus aina kasvab.

Meeskond VAKUUM TÄIS ehitab ümber tabelite ja indeksite sisu ning jätab neisse ainult asjakohased andmed. Paisumise kõrvaldamiseks töötab see suurepäraselt, kuid selle täitmise ajal tabatakse tabeli eksklusiivne lukk (AccessExclusiveLock), mis ei võimalda selles tabelis päringuid täita, isegi valib. Kui saate oma teenuse või selle osa mõneks ajaks peatada (sõltuvalt andmebaasi ja riistvara suurusest kümnetest minutitest kuni mitme tunnini), on see valik parim. Kahjuks ei ole meil aega plaanilise hoolduse ajal VACUUM FULL'i käivitada, mistõttu see meetod meile ei sobi.

Meeskond KLASTER Ehitab tabelite sisu uuesti üles samamoodi nagu VACUUM FULL, kuid võimaldab määrata indeksi, mille järgi andmed füüsiliselt kettale järjestatakse (kuid edaspidi pole järjekord uute ridade puhul garanteeritud). Teatud olukordades on see hea optimeerimine paljude päringute jaoks – mitme kirje lugemisel indeksi järgi. Käsu miinuseks on sama, mis VACUUM FULL-il – see lukustab töötamise ajal laua.

Meeskond REINDEKS sarnane kahe eelmisega, kuid loob uuesti konkreetse indeksi või kõik tabeli indeksid. Lukud on veidi nõrgemad: ShareLock tabelis (takistab muudatusi, kuid võimaldab valida) ja AccessExclusiveLock uuesti ülesehitaval indeksil (blokeerib seda indeksit kasutavad päringud). Postgresi 12. versioonis ilmus aga parameeter SAMAGA, mis võimaldab teil indeksit uuesti üles ehitada ilma samaaegset kirjete lisamist, muutmist või kustutamist blokeerimata.

Postgresi varasemates versioonides saate saavutada sama tulemuse nagu REINDEX SAMAGA, kasutades LOO INDEKSI SAMAGA. See võimaldab luua indeksi ilma range lukustamiseta (ShareUpdateExclusiveLock, mis ei sega paralleelpäringuid), seejärel asendada vana register uuega ja kustutada vana register. See võimaldab teil kõrvaldada indeksi turse ilma rakendust segamata. Oluline on arvestada, et indeksite taastamisel tekib ketta alamsüsteemile täiendav koormus.

Seega, kui indeksite puhul on võimalusi puhitus "lennult" kõrvaldada, siis tabelite jaoks neid pole. Siin tulevad mängu mitmesugused välised laiendused: pg_repack (endine pg_reorg), pgcompact, pgkompaktable ja teised. Selles artiklis ma neid ei võrdle ja räägin ainult pg_repackist, mida me pärast mõningast muutmist ise kasutame.

Kuidas pg_repack töötab

Postgres: bloat, pg_repack ja edasilükatud piirangud
Oletame, et meil on täiesti tavaline tabel – indeksite, piirangutega ja kahjuks ka bloatiga. Rakenduse pg_repack esimene samm on logitabeli loomine, et salvestada andmed kõigi muudatuste kohta selle töötamise ajal. Päästik kordab neid muudatusi iga lisamise, värskendamise ja kustutamise korral. Seejärel luuakse tabel, mis on struktuurilt sarnane algsele, kuid ilma indeksite ja piiranguteta, et mitte aeglustada andmete sisestamise protsessi.

Järgmisena edastab pg_repack andmed vanast tabelist uude tabelisse, filtreerides automaatselt välja kõik ebaolulised read ja seejärel loob uue tabeli jaoks indeksid. Kõigi nende toimingute tegemise ajal kogunevad logitabelisse muudatused.

Järgmine samm on muudatuste ülekandmine uude tabelisse. Migreerimine viiakse läbi mitme iteratsiooniga ja kui logitabelisse on jäänud vähem kui 20 kirjet, omandab pg_repack tugeva lukustuse, migreerib uusimad andmed ja asendab vana tabeli uuega Postgresi süsteemitabelites. See on ainus ja väga lühike aeg, mil te ei saa lauaga töötada. Pärast seda vana tabel ja tabel koos logidega kustutatakse ning failisüsteemis vabaneb ruumi. Protsess on lõppenud.

Teoorias tundub kõik suurepärane, aga mis juhtub praktikas? Testisime pg_repacki koormuseta ja koormuse all ning kontrollisime selle toimimist enneaegse seiskamise korral (ehk kasutades Ctrl+C). Kõik testid olid positiivsed.

Läksime toidupoodi – ja siis ei läinud kõik nii, nagu ootasime.

Esimene pannkook müügis

Esimeses klastris saime veateate unikaalse piirangu rikkumise kohta:

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

Sellel piirangul oli automaatselt loodud nimi index_16508 – selle lõi pg_repack. Selle koostises sisalduvate atribuutide põhjal määrasime kindlaks sellele vastava "meie" piirangu. Probleemiks osutus see, et see ei ole täiesti tavaline piirang, vaid edasi lükatud (edasilükatud piirang), st. selle kontrollimine toimub hiljem kui sql-käsk, mis toob kaasa ootamatuid tagajärgi.

Edasilükatud piirangud: miks neid vaja on ja kuidas need toimivad

Väike teooria edasilükatud piirangute kohta.
Vaatleme lihtsat näidet: meil on autode tabel-viiteraamat, millel on kaks atribuuti - auto nimi ja järjekord kataloogis.
Postgres: bloat, pg_repack ja edasilükatud piirangud

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



Oletame, et meil oli vaja vahetada esimene ja teine ​​auto. Lihtne lahendus on värskendada esimene väärtus teiseks ja teine ​​esimeseks:

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

Kuid selle koodi käivitamisel eeldame piirangute rikkumist, kuna väärtuste järjekord tabelis on kordumatu:

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

Kuidas ma saan seda teisiti teha? Esimene võimalus: lisage tellimusele lisaväärtuse asendus, mida tabelis kindlasti ei eksisteeri, näiteks "-1". Programmeerimises nimetatakse seda "kahe muutuja väärtuste vahetamiseks kolmandaga". Selle meetodi ainus puudus on täiendav värskendus.

Teine võimalus: kujundage tabel ümber, et kasutada täisarvude asemel tellimuse väärtuse jaoks ujukoma tüüpi andmetüüpi. Seejärel, kui värskendate väärtust näiteks 1-lt 2.5-le, jääb esimene kirje automaatselt teise ja kolmanda vahele. See lahendus töötab, kuid sellel on kaks piirangut. Esiteks ei tööta see teie jaoks, kui väärtust kasutatakse kuskil liideses. Teiseks, olenevalt andmetüübi täpsusest on teil enne kõigi kirjete väärtuste ümberarvutamist piiratud arv võimalikke sisestusi.

Kolmas võimalus: muutke piirang edasi lükatuks, nii et seda kontrollitakse ainult kohustuse täitmise ajal:

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

Kuna meie esialgse taotluse loogika tagab, et kõik väärtused on sidumise ajal unikaalsed, siis see õnnestub.

Eespool käsitletud näide on muidugi väga sünteetiline, kuid paljastab idee. Oma rakenduses kasutame edasilükatud piiranguid, et rakendada loogikat, mis vastutab konfliktide lahendamise eest, kui kasutajad töötavad samaaegselt tahvli jagatud vidinaobjektidega. Selliste piirangute kasutamine võimaldab meil rakenduse koodi pisut lihtsamaks muuta.

Üldiselt, olenevalt piirangu tüübist, on Postgresil nende kontrollimiseks kolm detailsuse taset: rea-, tehingu- ja avaldisetasemed.
Postgres: bloat, pg_repack ja edasilükatud piirangud
Allikas: begriffid

CHECK ja NOT NULL on alati kontrollitud rea tasemel, muude piirangute jaoks, nagu tabelist näha, on erinevaid võimalusi. Saate rohkem lugeda siin.

Lühidalt kokkuvõtteks võib öelda, et edasilükatud piirangud pakuvad paljudes olukordades paremini loetavat koodi ja vähem käske. Kuid selle eest peate maksma silumisprotsessi keerulisemaks muutmisega, kuna tõrke ilmnemise hetk ja sellest teadasaamise hetk on ajaliselt eraldatud. Teine võimalik probleem on see, et planeerija ei pruugi alati optimaalset plaani koostada, kui päring hõlmab edasilükatud piirangut.

Pg_repacki täiustamine

Oleme käsitlenud, mis on edasilükatud piirangud, kuid kuidas need on meie probleemiga seotud? Meenutagem varem saadud viga:

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

See ilmneb andmete kopeerimisel logitabelist uude tabelisse. See tundub imelik, sest... logitabelis olevad andmed on seotud lähtetabelis olevate andmetega. Kui nad vastavad algse tabeli piirangutele, kuidas saavad nad samu piiranguid uues tabelis rikkuda?

Nagu selgub, peitub probleemi juur pg_repack eelmises etapis, mis loob ainult indeksid, kuid mitte piiranguid: vanal tabelis oli kordumatu piirang ja uus lõi selle asemel ainulaadse indeksi.

Postgres: bloat, pg_repack ja edasilükatud piirangud

Siinkohal on oluline märkida, et kui piirang on normaalne ja mitte edasi lükatud, siis selle asemel loodud kordumatu indeks on samaväärne selle piiranguga, sest Postgresi kordumatuid piiranguid rakendatakse ainulaadse indeksi loomisega. Kuid edasilükatud piirangu puhul ei ole käitumine sama, sest indeksit ei saa edasi lükata ja seda kontrollitakse alati sql-käsu täitmise ajal.

Seega seisneb probleemi olemus kontrollimise "viivituses": algses tabelis toimub see sissekandmise ajal ja uues tabelis sql-käsu täitmise ajal. See tähendab, et peame tagama, et kontrollid teostatakse mõlemal juhul ühtemoodi: kas alati viivitusega või alati kohe.

Millised ideed meil siis olid?

Looge edasilükatud indeksiga sarnane indeks

Esimene idee on viia mõlemad kontrollid läbi koheses režiimis. See võib tekitada mitmeid valepositiivseid piiranguid, kuid kui neid on vähe, ei tohiks see kasutajate tööd mõjutada, kuna sellised konfliktid on nende jaoks tavaline olukord. Need tekivad näiteks siis, kui kaks kasutajat hakkavad sama vidinat korraga redigeerima ja teise kasutaja kliendil pole aega saada teavet, et vidin on juba esimese kasutaja poolt redigeerimiseks blokeeritud. Sellises olukorras keeldub server teisest kasutajast ja selle klient tühistab muudatused ja blokeerib vidina. Veidi hiljem, kui esimene kasutaja on toimetamise lõpetanud, saab teine ​​​​teabe, et vidin pole enam blokeeritud ja saab oma tegevust korrata.

Postgres: bloat, pg_repack ja edasilükatud piirangud

Tagamaks, et kontrollid oleksid alati edasilükamata režiimis, lõime uue indeksi, mis sarnaneb algse edasilükatud piiranguga:

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

Testkeskkonnas saime vaid paar oodatud viga. Edu! Käitasime pg_repacki uuesti tootmises ja saime töötunni jooksul esimeses klastris 5 viga. See on vastuvõetav tulemus. Kuid juba teises klastris suurenes vigade arv oluliselt ja tuli pg_repack peatada.

Miks see juhtus? Vea ilmnemise tõenäosus sõltub sellest, kui palju kasutajaid töötab samaaegselt samade vidinatega. Ilmselt oli sel hetkel esimesse klastrisse salvestatud andmetega konkurentsimuutusi tunduvalt vähem kui teistel, s.t. meil lihtsalt "vedas".

Idee ei töötanud. Sel hetkel nägime veel kahte lahendust: kirjutage oma rakenduse kood ümber, et loobuda edasilükatud piirangutest, või "õpetage" pg_repack nendega töötama. Valisime teise.

Asendage uues tabelis olevad indeksid algse tabeli edasilükatud piirangutega

Revisjoni eesmärk oli ilmne - kui algsel tabelis on edasilükatud piirang, siis uue jaoks peate looma sellise piirangu, mitte indeksi.

Muudatuste testimiseks kirjutasime lihtsa testi:

  • tabel edasilükatud piirangu ja ühe kirjega;
  • sisestada andmed tsüklisse, mis on vastuolus olemasoleva kirjega;
  • tee uuendus – andmed ei ole enam vastuolus;
  • teha muudatusi.

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;

Algne pg_repacki versioon jooksis alati esimesel sisestamisel kokku, muudetud versioon töötas vigadeta. Suurepärane.

Läheme tootmisse ja saame jälle vea logitabelist uude kopeerimisel:

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

Klassikaline olukord: testkeskkondades kõik töötab, aga tootmises mitte?!

APPLY_COUNT ja kahe partii ristmik

Hakkasime koodi sõna otseses mõttes rida-realt analüüsima ja avastasime olulise punkti: andmed kantakse logitabelist uude partiidena, konstant APPLY_COUNT näitas partii suurust:

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

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

Probleem on selles, et algse tehingu andmed, mille puhul mitmed toimingud võivad ülekandmisel piirangut rikkuda, võivad sattuda kahe partii ristmikule – pooled käskudest sooritatakse esimeses partiis ja teine ​​pool. teises. Ja siin olenevalt õnnest: kui meeskonnad esimeses partiis midagi ei riku, siis on kõik korras, aga kui rikuvad, siis tekib viga.

APPLY_COUNT võrdub 1000 kirjega, mis selgitab, miks meie testid olid edukad – need ei hõlmanud "partiiühenduse" juhtumit. Kasutasime kahte käsku - sisesta ja värskenda, seega paigutati alati pakk täpselt 500 kahe käsu tehingut ja meil ei esinenud probleeme. Pärast teise värskenduse lisamist lakkas meie muudatus töötamast:

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;

Seega on järgmiseks ülesandeks jälgida, et ühes tehingus muudetud algse tabelist andmed jõuaksid uude tabelisse ka ühe tehingu raames.

Pakkimisest keeldumine

Ja jälle oli meil kaks lahendust. Esiteks: loobugem täielikult partiideks jagamisest ja edastame andmed ühe tehinguga. Selle lahenduse plussiks oli lihtsus – vajalikud koodimuudatused olid minimaalsed (muide, vanemates versioonides töötas pg_reorg täpselt nii). Kuid on probleem – me loome pikaajalist tehingut ja see, nagu varem öeldud, on oht uue paisumise tekkele.

Teine lahendus on keerulisem, kuid ilmselt õigem: loo logitabelisse veerg selle tehingu identifikaatoriga, mis tabelisse andmeid lisas. Seejärel saame andmete kopeerimisel need selle atribuudi järgi rühmitada ja tagada, et seotud muudatused kantakse kokku. Partii moodustatakse mitmest tehingust (või ühest suurest) ja selle suurus varieerub sõltuvalt sellest, kui palju andmeid nendes tehingutes muudeti. Oluline on tähele panna, et kuna erinevate tehingute andmed sisenevad logitabelisse juhuslikus järjekorras, ei ole neid enam võimalik järjestikku lugeda, nagu see oli varem. Seqscan iga päringu jaoks koos tx_id järgi filtreerimisega on liiga kallis, indeksit on vaja, kuid see aeglustab ka meetodi tööd selle värskendamise tõttu. Üldiselt, nagu alati, peate midagi ohverdama.

Niisiis otsustasime alustada esimesest võimalusest, kuna see on lihtsam. Esiteks oli vaja aru saada, kas pikaajaline tehing on tõeline probleem. Kuna põhiline andmete ülekandmine vanast tabelist uude toimub ka ühe pika tehinguga, siis moondus küsimus küsimuseks "kui palju me seda tehingut suurendame?" Esimese tehingu kestus sõltub peamiselt tabeli suurusest. Uue kestus sõltub sellest, kui palju muudatusi andmete edastamise käigus tabelisse koguneb, s.t. koormuse intensiivsuse kohta. Pg_repack käitamine toimus minimaalse teenusekoormuse ajal ja muudatuste maht oli tabeli algse suurusega võrreldes ebaproportsionaalselt väike. Otsustasime, et uue tehingu tegemise aja võiks unarusse jätta (võrdluseks keskmiselt 1 tund ja 2-3 minutit).

Katsed olid positiivsed. Käivitage ka tootmine. Selguse huvides on siin pilt ühe andmebaasi suurusega pärast käivitamist:

Postgres: bloat, pg_repack ja edasilükatud piirangud

Kuna jäime selle lahendusega igati rahule, siis teist me juurutada ei proovinud, vaid kaalume võimalust seda laienduse arendajatega arutada. Meie praegune redaktsioon pole kahjuks veel avaldamiseks valmis, kuna lahendasime probleemi ainult ainulaadsete edasilükatud piirangutega ja täieõigusliku plaastri jaoks on vaja pakkuda tuge ka teistele tüüpidele. Loodame, et saame seda ka tulevikus teha.

Võib-olla on teil küsimus, miks me sellesse loosse pg_repack modifikatsiooniga üldse kaasa lõime ja ei kasutanud näiteks selle analooge? Mingil hetkel mõtlesime ka sellele, kuid positiivne kogemus selle varasemast kasutamisest ilma edasilükatud piiranguteta tabelitel ajendas meid proovima probleemi olemust mõista ja seda parandada. Lisaks nõuab muude lahenduste kasutamine ka aega testide läbiviimiseks, mistõttu otsustasime, et proovime esmalt selles probleemi lahendada ja kui saame aru, et seda mõistliku aja jooksul teha ei saa, siis hakkame otsima analooge. .

Järeldused

Mida saame oma kogemuse põhjal soovitada:

  1. Jälgige oma turset. Seireandmete põhjal saate aru, kui hästi on autovaakum konfigureeritud.
  2. Reguleerige AUTOVACUUM, et hoida puhitus vastuvõetaval tasemel.
  3. Kui puhitus alles kasvab ja te ei saa sellest valmis vahenditega üle, ärge kartke kasutada väliseid laiendusi. Peaasi, et kõik hästi testida.
  4. Ärge kartke muuta väliseid lahendusi vastavalt oma vajadustele – mõnikord võib see olla tõhusam ja isegi lihtsam kui enda koodi muutmine.

Allikas: www.habr.com

Lisa kommentaar