Postgres: opblaas, pg_repack en uitgestelde beperkings

Postgres: opblaas, pg_repack en uitgestelde beperkings

Die effek van opblaastabelle en indekse (opblaas) is wyd bekend en is nie net in Postgres teenwoordig nie. Daar is maniere om dit "uit die boks" te hanteer soos VACUUM FULL of CLUSTER, maar hulle sluit tafels tydens werking en kan dus nie altyd gebruik word nie.

Die artikel sal 'n bietjie teorie bevat oor hoe opblaas plaasvind, hoe jy dit kan hanteer, oor uitgestelde beperkings en die probleme wat dit meebring om die pg_repack-uitbreiding te gebruik.

Hierdie artikel is gebaseer op my toespraak by PgConf.Russia 2020.

Hoekom is daar 'n opblaas

Postgres is gebaseer op 'n multi-weergawe model (MVCC). Die essensie daarvan is dat elke ry in die tabel verskeie weergawes kan hê, terwyl transaksies nie meer as een van hierdie weergawes sien nie, maar nie noodwendig dieselfde een nie. Dit laat verskeie transaksies gelyktydig werk en het min tot geen effek op mekaar nie.

Dit is duidelik dat al hierdie weergawes gehou moet word. Postgres werk bladsy vir bladsy met geheue, en 'n bladsy is die minimum hoeveelheid data wat van skyf gelees of geskryf kan word. Kom ons kyk na 'n klein voorbeeld om te verstaan ​​hoe dit gebeur.

Kom ons sê ons het 'n tabel waarby ons verskeie rekords gevoeg het. Die eerste bladsy van die lêer waar die tabel gestoor word, het nuwe data. Dit is lewendige weergawes van rye wat beskikbaar is vir ander transaksies na die commit (vir eenvoud sal ons aanneem dat die isolasievlak Read Committed is).

Postgres: opblaas, pg_repack en uitgestelde beperkings

Ons het toe een van die inskrywings opgedateer en dus die ou weergawe as verouderd gemerk.

Postgres: opblaas, pg_repack en uitgestelde beperkings

Stap vir stap, met die opdatering en verwydering van ry weergawes, het ons 'n bladsy gekry waarin ongeveer die helfte van die data "rommel" is. Hierdie data is nie sigbaar vir enige transaksie nie.

Postgres: opblaas, pg_repack en uitgestelde beperkings

Postgres het 'n meganisme VACUUM, wat verouderde weergawes skoonmaak en plek maak vir nuwe data. Maar as dit nie aggressief genoeg gekonfigureer is nie of besig is om in ander tabelle te werk, dan bly die "rommeldata" oor, en ons moet addisionele bladsye vir nuwe data gebruik.

So in ons voorbeeld sal die tabel op 'n sekere tydstip uit vier bladsye bestaan, maar daar sal net die helfte van die lewendige data daarin wees. As gevolg hiervan, wanneer ons toegang tot die tabel verkry, sal ons baie meer data uitlees as wat nodig is.

Postgres: opblaas, pg_repack en uitgestelde beperkings

Selfs al verwyder VACUUM nou alle irrelevante ry-weergawes, sal die situasie nie dramaties verbeter nie. Ons sal vrye spasie in bladsye of selfs hele bladsye hê vir nuwe reëls, maar ons sal steeds meer data lees as wat ons nodig het.
Terloops, as 'n heeltemal leë bladsy (die tweede in ons voorbeeld) aan die einde van die lêer was, kan VACUUM dit afsny. Maar nou is sy in die middel, so niks kan met haar gedoen word nie.

Postgres: opblaas, pg_repack en uitgestelde beperkings

Wanneer die aantal sulke leë of baie yl bladsye groot word, wat bloat genoem word, begin dit prestasie beïnvloed.

Alles hierbo beskryf is die meganika van die voorkoms van opblaas in tabelle. In indekse gebeur dit op baie dieselfde manier.

Het ek 'n opblaas?

Daar is verskeie maniere om te bepaal of jy 'n opblaas het. Die idee van die eerste is om Postgres interne statistieke te gebruik, wat benaderde inligting bevat oor die aantal rye in tabelle, die aantal "lewendige" rye, ens. Daar is baie variasies van klaargemaakte skrifte op die internet. Ons het as basis geneem skrif van PostgreSQL Experts, wat tafelbloat saam met roosterbrood en bloat btree-indekse kan evalueer. In ons ervaring is die fout 10-20%.

Nog 'n manier is om die uitbreiding te gebruik pgstattuple, wat jou toelaat om binne die bladsye te kyk en beide die geskatte en die presiese waarde van opblaas te kry. Maar in die tweede geval sal jy die hele tabel moet skandeer.

'n Klein hoeveelheid opblaas, tot 20%, is aanvaarbaar. Dit kan beskou word as 'n analoog van die vulfaktor vir tafels и indekse. By 50% en hoër kan prestasieprobleme begin.

Maniere om opblaas te hanteer

Daar is verskeie out-of-the-box maniere om opblaas in Postgres te hanteer, maar dit is ver van altyd en sal dalk nie almal pas nie.

Stel AUTOVACUUM op sodat opblaas nie voorkom nie. En om meer presies te wees, om dit op 'n aanvaarbare vlak vir jou te hou. Dit lyk na 'n "kaptein" se raad, maar in werklikheid is dit nie altyd maklik om te bereik nie. Byvoorbeeld, jy het 'n aktiewe ontwikkeling met 'n gereelde verandering in die dataskema, of 'n soort datamigrasie vind plaas. As gevolg hiervan kan jou vragprofiel gereeld verander en is dit geneig om anders te wees vir verskillende tabelle. Dit beteken dat jy voortdurend 'n bietjie voor die kurwe moet wees en AUTOVAKUUM moet aanpas by die veranderende profiel van elke tafel. Maar dit is duidelik dat dit nie maklik is om te doen nie.

Nog 'n algemene rede waarom AUTOVACUUM versuim om tabelle te verwerk, is die teenwoordigheid van langlopende transaksies wat verhoed dat dit data skoonmaak as gevolg van die feit dat dit vir hierdie transaksies beskikbaar is. Die aanbeveling hier is ook voor die hand liggend - raak ontslae van "hangende" transaksies en verminder die tyd van aktiewe transaksies. Maar as die las op jou toepassing 'n baster van OLAP en OLTP is, kan jy gelyktydig baie gereelde opdaterings en kort navrae hê, sowel as lang bewerkings, soos die bou van 'n verslag. In so 'n situasie moet u daaraan dink om die las op verskillende basisse te versprei, wat u in staat sal stel om elkeen van hulle te verfyn.

Nog 'n voorbeeld - selfs al is die profiel homogeen, maar die databasis is onder 'n baie hoë las, dan kan selfs die mees aggressiewe AUTOVACUUM nie in staat wees om dit te hanteer nie, en opblaas sal voorkom. Skaal (vertikaal of horisontaal) is die enigste oplossing.

Hoe om in 'n situasie te wees wanneer jy AUTOVACUUM gekonfigureer het, maar opblaas bly groei.

Span VAKUUM VOL herbou die inhoud van tabelle en indekse en laat slegs bygewerkte data daarin. Om opblaas uit te skakel, werk dit perfek, maar tydens die uitvoering daarvan word 'n eksklusiewe slot op die tafel (AccessExclusiveLock) vasgelê, wat nie navrae na hierdie tabel sal toelaat nie, selfs kies. As u dit kan bekostig om u diens of 'n gedeelte daarvan vir 'n geruime tyd te stop (van tien minute tot 'n paar uur, afhangende van die grootte van die databasis en u hardeware), dan is hierdie opsie die beste. Ons het ongelukkig nie tyd om VAKUUM VOL te laat loop tydens die geskeduleerde instandhouding nie, so hierdie metode pas ons nie.

Span KLUSTER herbou die inhoud van tabelle op dieselfde manier as VACUUM FULL, terwyl dit jou toelaat om 'n indeks te spesifiseer waarvolgens die data fisies op skyf georden sal word (maar die volgorde word nie vir nuwe rye in die toekoms gewaarborg nie). In sekere situasies is dit 'n goeie optimalisering vir 'n aantal navrae - met die lees van verskeie rekords in die indeks. Die nadeel van die opdrag is dieselfde as dié van VACUUM FULL - dit sluit die tafel tydens werking.

Span HERINDEKS soortgelyk aan die vorige twee, maar herbou 'n spesifieke indeks of alle indekse op 'n tabel. Slotte is effens swakker: ShareLock op 'n tafel (voorkom wysigings, maar laat kies toe) en AccessExclusiveLock op 'n herboubare indeks (blokkeer navrae wat hierdie indeks gebruik). Postgres 12 het egter die opsie bekendgestel GELYKLIK, wat jou toelaat om 'n indeks te herbou sonder om gelyktydige byvoeging, wysiging of verwydering van rekords te blokkeer.

In vroeëre weergawes van Postgres kan u 'n resultaat bereik wat soortgelyk is aan REINDEX GELYKLIK met SKEP GELYKTYDIG INDEKS. Dit laat jou toe om 'n indeks sonder 'n sterk slot te skep (ShareUpdateExclusiveLock, wat nie inmeng met parallelle navrae nie), dan die ou indeks met 'n nuwe een te vervang en die ou indeks uit te vee. Dit laat jou toe om indeksopblaas uit te skakel sonder om met jou toepassing in te meng. Dit is belangrik om in ag te neem dat wanneer indekse herbou word, daar 'n bykomende las op die skyfsubstelsel sal wees.

Dus, as daar maniere is vir indekse om warm opblaas uit te skakel, dan is daar geen vir tabelle nie. Dit is waar eksterne uitbreidings ter sprake kom: pg_herpak (voorheen pg_reorg), pgcompact, pgcompacttable en ander. Binne die raamwerk van hierdie artikel sal ek hulle nie vergelyk nie en sal net praat oor pg_repack, wat ons, na 'n bietjie verfyning, tuis gebruik.

Hoe pg_repack werk

Postgres: opblaas, pg_repack en uitgestelde beperkings
Kom ons sê ons het 'n doodgewone tabel - met indekse, beperkings en, ongelukkig, met opblaas. As 'n eerste stap skep pg_repack 'n logtabel om tred te hou met alle veranderinge terwyl dit aan die gang is. Die sneller sal hierdie veranderinge na elke invoeging, opdatering en uitvee herhaal. Dan word 'n tabel geskep wat soortgelyk is aan die oorspronklike in struktuur, maar sonder indekse en beperkings, om nie die proses van die invoeging van data te vertraag nie.

Vervolgens dra pg_repack data van die ou tabel na die nuwe tabel oor, filter outomaties alle irrelevante rye uit, en skep dan indekse vir die nuwe tabel. Tydens die uitvoering van al hierdie bewerkings word veranderinge in die logtabel opgehoop.

Die volgende stap is om die veranderinge na die nuwe tabel oor te dra. Die migrasie word in verskeie iterasies gedoen, en wanneer daar minder as 20 inskrywings in die logtabel oor is, kry pg_repack 'n sterk slot, migreer die nuutste data en vervang die ou tabel met die nuwe een in die Postgres-stelseltabelle. Dit is die enigste en baie kort tydjie wanneer jy nie met die tafel sal kan werk nie. Daarna word die ou tabel en die tabel met logs uitgevee en spasie in die lêerstelsel vrygemaak. Proses voltooi.

In teorie lyk alles goed, maar wat van in die praktyk? Ons het pg_repack sonder lading en onder lading getoets, en die werking daarvan nagegaan in die geval van 'n voortydige stop (met ander woorde, deur Ctrl+C). Alle toetse was positief.

Ons het na die prod gegaan – en toe loop alles verkeerd, soos ons verwag het.

Eerste pannekoek te koop

Op die eerste groepering het ons 'n fout gekry oor 'n unieke beperkingoortreding:

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

Hierdie beperking het die outo-gegenereerde naam index_16508 gehad, geskep deur pg_repack. Deur die eienskappe wat in die samestelling daarvan ingesluit is, het ons "ons" beperking bepaal wat daarmee ooreenstem. Die probleem blyk te wees dat dit nie heeltemal 'n gewone beperking is nie, maar 'n vertraagde een (uitgestelde beperking), d.w.s. die validering daarvan word later as die sql-opdrag uitgevoer, wat tot onverwagte gevolge lei.

Uitgestelde beperkings: waarom dit nodig is en hoe dit werk

'n Bietjie teorie oor uitgestelde beperkings.
Beskou 'n eenvoudige voorbeeld: ons het 'n motorgidstabel met twee eienskappe - die naam en volgorde van die motor in die gids.
Postgres: opblaas, pg_repack en uitgestelde beperkings

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



Gestel ons moes die eerste en tweede motors op plekke omruil. Die kop-aan-oplossing is om die eerste waarde op te dateer na die tweede, en die tweede na die eerste:

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

Maar wanneer ons hierdie kode uitvoer, word daar van ons verwag om 'n beperkingoortreding te kry omdat die volgorde van die waardes in die tabel uniek is:

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

Hoe om dit anders te doen? Opsie een: voeg 'n bykomende vervanging van die waarde by met 'n bestelling wat gewaarborg is om nie in die tabel te bestaan ​​nie, byvoorbeeld "-1". In programmering word dit genoem "om die waardes van twee veranderlikes deur 'n derde uit te ruil." Die enigste nadeel van hierdie metode is die ekstra opdatering.

Opsie twee: Herontwerp die tabel om 'n swaaipuntdatatipe vir die eksponentwaarde in plaas van heelgetalle te gebruik. Dan, wanneer die waarde van 1, byvoorbeeld, na 2.5 opgedateer word, sal die eerste inskrywing outomaties tussen die tweede en derde "staan". Hierdie oplossing werk, maar daar is twee beperkings. Eerstens sal dit nie vir jou werk as die waarde iewers in die koppelvlak gebruik word nie. Tweedens, afhangende van die akkuraatheid van die datatipe, sal u 'n beperkte aantal moontlike invoegings hê voordat u die waardes van alle rekords herbereken.

Opsie drie: maak die beperking uitgestel sodat dit slegs gekontroleer word ten tyde van die commit:

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

Aangesien die logika van ons aanvanklike versoek verseker dat alle waardes uniek is teen die tyd dat die verbintenis gemaak word, sal die verbintenis slaag.

Die voorbeeld wat hierbo bespreek is, is natuurlik baie sinteties, maar dit openbaar die idee. In ons toepassing gebruik ons ​​uitgestelde beperkings om die logika te implementeer wat verantwoordelik is vir die oplossing van konflikte wanneer gebruikers terselfdertyd met gedeelde legstukvoorwerpe op die bord interaksie het. Die gebruik van sulke beperkings stel ons in staat om die toepassingskode 'n bietjie eenvoudiger te maak.

In die algemeen, afhangende van die beperkingstipe in Postgres, is daar drie vlakke van granulariteit van hul validering: ry, transaksie en uitdrukking.
Postgres: opblaas, pg_repack en uitgestelde beperkings
Bron: begriffs

CHECK en NOT NULL word altyd op die ryvlak gekontroleer, vir ander beperkings, soos uit die tabel gesien kan word, is daar verskillende opsies. Jy kan meer lees hier.

Om kortliks op te som, uitgestelde beperkings in 'n aantal situasies lei tot meer leesbare kode en minder opdragte. U moet egter hiervoor betaal deur die ontfoutingsproses te bemoeilik, aangesien die oomblik wat die fout voorkom en die oomblik wat u daarvan leer, betyds geskei word. Nog 'n moontlike probleem is dat die skeduleerder dalk nie altyd 'n optimale plan kan bou as 'n vertraagde beperking by die navraag betrokke is nie.

Verbetering pg_repack

Ons het gedek wat uitgestelde beperkings is, maar hoe hou dit verband met ons probleem? Onthou die fout wat ons vroeër gekry het:

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

Dit vind plaas wanneer data van die logtabel na 'n nuwe tabel gekopieer word. Dit lyk vreemd, want die data in die logtabel word saam met die data in die oorspronklike tabel gecommit. As hulle aan die oorspronklike tabel se beperkings voldoen, hoe kan hulle dieselfde beperkings in die nuwe een oortree?

Soos dit geblyk het, lê die wortel van die probleem in die vorige stap van pg_repack, wat slegs indekse skep, maar nie beperkings nie: die ou tabel het 'n unieke beperking gehad, en die nuwe een het eerder 'n unieke indeks geskep.

Postgres: opblaas, pg_repack en uitgestelde beperkings

Dit is belangrik om hier op te let dat as die beperking normaal is en nie uitgestel is nie, dan is die unieke indeks wat in plaas daarvan geskep word gelykstaande aan hierdie beperking, want unieke beperkings in Postgres word geïmplementeer deur 'n unieke indeks te skep. Maar in die geval van uitgestelde beperking, is die gedrag nie dieselfde nie, want die indeks kan nie uitgestel word nie en word altyd nagegaan wanneer die sql-opdrag uitgevoer word.

Die kern van die probleem lê dus in die "uitgestelde" kontrole: in die oorspronklike tabel vind dit plaas tydens die commit, en in die nuwe een, ten tyde van die uitvoering van die sql-opdrag. Ons moet dus seker maak dat die kontroles in beide gevalle op dieselfde manier uitgevoer word: óf altyd vertraag, óf altyd onmiddellik.

So watter idees het ons gehad.

Skep indeks soortgelyk aan uitgestelde

Die eerste idee is om beide kontroles in onmiddellike modus uit te voer. Dit kan aanleiding gee tot verskeie vals positiewe van die beperking, maar as daar min van hulle is, behoort dit nie die werk van gebruikers te beïnvloed nie, aangesien sulke konflikte 'n normale situasie vir hulle is. Hulle kom byvoorbeeld voor wanneer twee gebruikers dieselfde legstuk op dieselfde tyd begin redigeer, en die kliënt van die tweede gebruiker het nie tyd om inligting te ontvang dat die legstuk reeds deur die eerste gebruiker geblokkeer is vir redigering nie. In so 'n situasie reageer die bediener op die tweede gebruiker met 'n weiering, en sy kliënt rol die veranderinge terug en sluit die legstuk. 'N Bietjie later, wanneer die eerste gebruiker die redigering voltooi, sal die tweede inligting ontvang dat die legstuk nie meer geblokkeer is nie, en sal sy aksie kan herhaal.

Postgres: opblaas, pg_repack en uitgestelde beperkings

Om te verseker dat tjeks altyd in onuitgestelde modus is, het ons 'n nuwe indeks geskep soortgelyk aan die oorspronklike uitgestelde beperking:

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

Op die toetsomgewing het ons slegs 'n paar verwagte foute ontvang. Sukses! Ons het pg_repack weer op prod gehardloop en het 5 foute op die eerste cluster gekry in 'n uur se werk. Dit is 'n aanvaarbare resultaat. Reeds op die tweede groep het die aantal foute egter aansienlik toegeneem en ons moes pg_repack stop.

Hoekom het dit gebeur? Die waarskynlikheid dat 'n fout sal voorkom, hang af van hoeveel gebruikers gelyktydig met dieselfde legstukke werk. Blykbaar was daar op daardie oomblik baie minder mededingende veranderinge met die data wat op die eerste groep gestoor is as op die res, m.a.w. ons is net "gelukkig".

Die idee het nie gewerk nie. Op daardie oomblik het ons twee ander oplossings gesien: herskryf ons toepassingskode om uitgestelde beperkings te laat vaar, of "leer" pg_repack om daarmee te werk. Ons het die tweede een gekies.

Vervang indekse in nuwe tabel met uitgestelde beperkings van oorspronklike tabel

Die doel van die hersiening was voor die hand liggend - as die oorspronklike tabel 'n uitgestelde beperking het, dan is dit vir die nuwe een nodig om so 'n beperking te skep, en nie 'n indeks nie.

Om ons veranderinge te toets, het ons 'n eenvoudige toets geskryf:

  • tabel met uitgestelde beperking en een rekord;
  • ons voeg data in die lus in wat bots met die bestaande rekord;
  • doen 'n opdatering - die data bots nie meer nie;
  • veranderinge pleeg.

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;

Die oorspronklike weergawe van pg_repack het altyd met die eerste invoeging neergestort, die gewysigde weergawe het sonder foute gewerk. Groot.

Ons gaan na prod en weer kry ons 'n fout in dieselfde fase van die kopiëring van data van die logtabel na 'n nuwe een:

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

'n Klassieke situasie: alles werk op toetsomgewings, maar nie op produksie nie?!

APPLY_COUNT en die aansluiting van twee groepe

Ons het begin om die kode letterlik reël vir reël te ontleed en 'n belangrike punt ontdek: data word in bondels van die logtabel na die nuwe een oorgedra, die APPLY_COUNT konstante het die grootte van die bondel aangedui:

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

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

Die probleem is dat die data van die oorspronklike transaksie, waarin verskeie bewerkings moontlik die beperking kan oortree, by die aansluiting van twee groepe tydens die oordrag kan beland - die helfte van die opdragte sal in die eerste bondel gepleeg word, en die ander helfte in die tweede. En hier, hoe gelukkig: as die spanne in die eerste bondel niks oortree nie, dan is alles reg, maar as hulle dit doen, vind 'n fout plaas.

APPLY_COUNT is gelyk aan 1000 rekords, wat verduidelik hoekom ons toetse suksesvol was - dit het nie die "batch junction"-geval gedek nie. Ons het twee opdragte gebruik - voeg in en werk op, so presies 500 transaksies van twee opdragte is altyd in 'n bondel geplaas en ons het nie probleme ondervind nie. Nadat ons die tweede opdatering bygevoeg het, het ons wysiging opgehou werk:

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;

Dus, die volgende taak is om seker te maak dat die data van die oorspronklike tabel wat in een transaksie verander is, ook binne een transaksie in die nuwe tabel kom.

Verwerping van groepering

En ons het weer twee oplossings gehad. Eerstens: kom ons weier om heeltemal in groepe te verdeel en maak die data-oordrag 'n enkele transaksie. Ten gunste van hierdie besluit was die eenvoud daarvan - die vereiste kodeveranderinge is minimaal (terloops, in ouer weergawes het pg_reorg so gewerk). Maar daar is 'n probleem - ons skep 'n langtermyntransaksie, en dit is, soos vroeër genoem, 'n bedreiging vir die ontstaan ​​van 'n nuwe opblaas.

Die tweede oplossing is meer ingewikkeld, maar waarskynlik meer korrek: skep 'n kolom in die logtabel met die identifiseerder van die transaksie wat data by die tabel gevoeg het. Wanneer ons dan data kopieer, kan ons dit volgens hierdie kenmerk groepeer en verseker dat verwante veranderinge saam oorgedra word. Die bondel sal uit verskeie transaksies (of een groot een) gevorm word en die grootte daarvan sal wissel na gelang van hoeveel data in hierdie transaksies verander is. Dit is belangrik om daarop te let dat aangesien die data van verskillende transaksies die logtabel in ewekansige volgorde binnegaan, dit nie meer moontlik sal wees om dit opeenvolgend te lees nie, soos voorheen. seqscan op elke versoek wat deur tx_id gefiltreer word, is te duur, jy benodig 'n indeks, maar dit sal ook die metode vertraag as gevolg van die bokoste om dit by te werk. Oor die algemeen, soos altyd, moet jy iets opoffer.

Ons het dus besluit om met die eerste opsie te begin, as 'n eenvoudiger een. Eerstens was dit nodig om te verstaan ​​of 'n lang transaksie 'n werklike probleem sou wees. Aangesien die hoofoordrag van data van die ou tabel na die nuwe een ook in een lang transaksie plaasvind, is die vraag omskep in "hoeveel sal ons hierdie transaksie verhoog?" Die duur van die eerste transaksie hang hoofsaaklik af van die grootte van die tafel. Die duur van die nuwe een hang af van hoeveel veranderinge in die tabel sal ophoop tydens die data-oordrag, d.w.s. op die intensiteit van die las. Die pg_repack-lopie het plaasgevind op 'n tyd van minimale dienslading, en die hoeveelheid verandering was onvergelykbaar klein in vergelyking met die oorspronklike tabelgrootte. Ons het besluit dat ons die tyd van 'n nuwe transaksie kan afskeep (ter vergelyking is die gemiddelde 1 uur en 2-3 minute).

Die eksperimente was positief. Begin ook te koop. Vir duidelikheid, hier is 'n prentjie met die grootte van een van die basisse na die lopie:

Postgres: opblaas, pg_repack en uitgestelde beperkings

Aangesien hierdie oplossing ons heeltemal gepas het, het ons nie probeer om die tweede een te implementeer nie, maar ons oorweeg die moontlikheid om dit met die ontwikkelaars van die uitbreiding te bespreek. Ons huidige hersiening is ongelukkig nog nie gereed vir publikasie nie, aangesien ons die probleem net opgelos het met unieke vertraagde beperkings, en vir 'n volwaardige pleister, moet ondersteuning vir ander tipes gemaak word. Ons hoop om dit in die toekoms te kan doen.

Miskien het jy 'n vraag, hoekom het ons selfs by hierdie storie betrokke geraak met die verfyning van pg_repack, en het ons nie byvoorbeeld sy analoë gebruik nie? Op 'n stadium het ons ook daaraan gedink, maar die positiewe ervaring om dit vroeër te gebruik, op tafels sonder vertraagde beperkings, het ons gemotiveer om die essensie van die probleem te probeer verstaan ​​en dit reg te stel. Boonop verg die gebruik van ander oplossings ook tyd om toetse uit te voer, daarom het ons besluit dat ons eers die probleem daarin sal probeer oplos, en as ons besef dat ons dit nie binne 'n redelike tyd kan doen nie, dan sal ons analoë begin oorweeg.

Bevindinge

Wat ons kan aanbeveel op grond van ons eie ervaring:

  1. Monitor jou opblaas. Op grond van die moniteringsdata sal jy kan verstaan ​​hoe goed outovakuum ingestel is.
  2. Stel AUTOVAKUUM om opblaas op 'n aanvaarbare vlak te hou.
  3. As die opblaas steeds groei en jy kan dit nie met gereedskap uit die boks hanteer nie, moenie bang wees om eksterne uitbreidings te gebruik nie. Die belangrikste ding is om alles goed te toets.
  4. Moenie bang wees om eksterne oplossings aan te pas om by jou behoeftes te pas nie – soms kan dit meer doeltreffend en selfs makliker wees as om jou eie kode te verander.

Bron: will.com

Voeg 'n opmerking