Postgres: bloat, pg_repack è limitazioni differite

Postgres: bloat, pg_repack è limitazioni differite

L'effettu di bloat nantu à e tavule è l'indici hè assai cunnisciutu è hè presente micca solu in Postgres. Ci sò manere di trattà cun ella fora di a scatula, cum'è VACUUM FULL o CLUSTER, ma chjappà e tavule durante l'operazione è per quessa ùn ponu micca sempre esse usate.

L'articulu cuntene una piccula teoria nantu à cumu si trova u bloat, cumu si pò cummattiri, nantu à e limitazioni differite è i prublemi chì portanu à l'usu di l'estensione pg_repack.

Stu articulu hè scrittu basatu nantu u mo discorsu à PgConf.Russia 2020.

Perchè u bloat accade?

Postgres hè basatu annantu à un mudellu multi-versione (MVCC). A so essenza hè chì ogni fila in a tavula pò avè parechje versioni, mentre chì e transazzione ùn vede micca più di una di queste versioni, ma micca necessariamente a stessa. Questu permette à parechje transazzioni di travaglià simultaneamente è ùn anu praticamente micca impattu l'un l'altru.

Ovviamente, tutte queste versioni deve esse guardatu. Postgres travaglia cù memoria pagina per pagina è una pagina hè a quantità minima di dati chì ponu esse leghje da u discu o scritti. Fighjemu un picculu esempiu per capisce cumu questu succede.

Diciamu chì avemu una tavula à quale avemu aghjustatu parechji registri. Novi dati sò apparsu in a prima pagina di u schedariu induve a tavula hè guardata. Quessi sò versioni in diretta di fila chì sò dispunibuli per altre transazzione dopu un cummit (per simplicità, assumeremu chì u livellu di isolamentu hè Read Committed).

Postgres: bloat, pg_repack è limitazioni differite

Dopu avemu aghjurnatu una di e entrate, marchendu cusì a vechja versione cum'è ùn hè più pertinente.

Postgres: bloat, pg_repack è limitazioni differite

Passu à passu, aghjurnà è sguassate versioni di fila, avemu finitu cù una pagina in quale circa a mità di e dati sò "basura". Questa dati ùn hè micca visibile à qualsiasi transazzione.

Postgres: bloat, pg_repack è limitazioni differite

Postgres hà un mecanismu VACUUM, chì pulisce e versioni obsoleti è face spaziu per novi dati. Ma s'ellu ùn hè micca cunfiguratu abbastanza aggressivu o hè occupatu à travaglià in altre tavule, allora "dati di basura" ferma, è avemu da utilizà pagine supplementari per novi dati.

Allora in u nostru esempiu, in un certu puntu in u tempu a tavula serà custituita da quattru pagine, ma solu a mità di questu cuntene dati in diretta. In u risultatu, quandu accede à a tavula, leghjemu assai più dati di ciò chì hè necessariu.

Postgres: bloat, pg_repack è limitazioni differite

Ancu s'è VACUUM avà sguassate tutte e versioni di fila irrilevanti, a situazione ùn migliurà dramaticamente. Averemu spaziu liberu in pagine o ancu pagine intere per e fila novi, ma avemu sempre leghje più dati di ciò chì hè necessariu.
A propositu, se una pagina completamente bianca (a seconda in u nostru esempiu) era à a fine di u schedariu, allora VACUUM puderia trimà. Ma avà hè in u mezu, cusì ùn si pò fà nunda cun ella.

Postgres: bloat, pg_repack è limitazioni differite

Quandu u numeru di tali pagine vacanti o assai sparse diventa grande, chì hè chjamatu bloat, cumencia à affettà u rendiment.

Tuttu ciò chì hè descrittu sopra hè a meccanica di l'occurrence di bloat in tavule. In l'indici, questu succede in quasi u listessu modu.

Aghju gonfia?

Ci hè parechje manere di determinà s'ellu avete bloat. L'idea di u primu hè di utilizà statistiche internu di Postgres, chì cuntene infurmazione apprussimativa nantu à u nùmeru di fila in tavule, u nùmeru di fila "live", etc. Pudete truvà parechje variazioni di scripts pronti in Internet. Avemu pigliatu cum'è una basa script da l'Esperti PostgreSQL, chì ponu valutà e tabelle di bloat cù l'indici di toast è bloat btree. In a nostra sperienza, u so errore hè 10-20%.

Un altru modu hè di utilizà l'estensione pgstattuple, chì vi permette di circà l'internu di e pagine è ottene un valore stimatu è esatta. Ma in u sicondu casu, vi tuccherà à scansà tutta a tavola.

Cunsideremu un picculu valore bloat, finu à u 20%, accettabile. Pò esse cunsideratu cum'è un analogu di fillfactor per tavuli и indici. À u 50% è sopra, i prublemi di rendiment ponu cumincià.

Modi di cummattiri bloat

Postgres hà parechje manere di trattà cù bloat out of the box, ma ùn sò micca sempre adattati per tutti.

Configurate AUTOVACUUM per chì u bloat ùn si faci micca. O più precisamente, per mantene à un livellu accettabile per voi. Questu pare u cunsigliu di "capitanu", ma in a realità questu ùn hè micca sempre faciule da ottene. Per esempiu, avete un sviluppu attivu cù cambiamenti rigulari à u schema di dati, o qualchì tipu di migrazione di dati hè accadutu. In u risultatu, u vostru prufilu di carica pò cambià spessu è varià tipicamente da tavola à tavola. Questu significa chì avete bisognu di travaglià constantemente un pocu avanti è aghjustate AUTOVACUUM à u prufilu cambiante di ogni tavula. Ma ovviamente questu ùn hè micca faciule da fà.

Un altru mutivu cumunu perchè AUTOVACUUM ùn pò micca seguità cù e tavule hè perchè ci sò transazzione longu chì impediscenu di pulizziari i dati chì sò dispunibuli per quelli transazzione. A ricunniscenza quì hè ancu evidenti - sguassate di e transacciones "pendenti" è minimizzà u tempu di transazzione attiva. Ma se a carica nantu à a vostra applicazione hè un hibridu di OLAP è OLTP, pudete avè simultaneamente assai aghjurnamenti frequenti è dumande brevi, è ancu operazioni à longu andà - per esempiu, custruisce un rapportu. In una tale situazione, vale a pena di pensà à sparghje a carica nantu à e diverse basi, chì permetterà più fine-tuning di ognunu di elli.

Un altru esempiu - ancu s'è u prufilu hè homogeneous, ma a basa di dati hè sottu à una carica assai altu, tandu ancu u AUTOVACUUM più aggressivu ùn pò micca affruntà, è bloat succede. Scaling (verticale o horizontale) hè l'unica suluzione.

Cosa da fà in una situazione induve avete stallatu AUTOVACUUM, ma u bloat cuntinueghja à cresce.

squadra VACUUM FULL ricustruisce u cuntenutu di e tavule è l'indici è lascia solu dati pertinenti in elli. Per eliminà bloat, funziona perfettamente, ma durante a so esicuzzioni un chjusu esclusivu nantu à a tavula hè catturatu (AccessExclusiveLock), chì ùn permettenu micca eseguisce dumande nantu à sta tavula, ancu selezziunate. Se pudete permette di piantà u vostru serviziu o parte di questu per qualchì tempu (da decine di minuti à parechje ore secondu a dimensione di a basa di dati è u vostru hardware), allora sta opzione hè u megliu. Sfurtunatamente, ùn avemu micca tempu per eseguisce VACUUM FULL durante u mantenimentu programatu, cusì stu metudu ùn hè micca adattatu per noi.

squadra CLUSTER Rebuilds u cuntenutu di e tavule in u listessu modu cum'è VACUUM FULL, ma permette di specificà un indice secondu chì i dati seranu fisicamenti urdinati nantu à u discu (ma in u futuru l'ordine ùn hè micca garantitu per i novi fila). In certe situazioni, questu hè una bona ottimisazione per una quantità di dumande - cù lettura di parechji registri per indice. U svantaghju di u cumandamentu hè u listessu cum'è quellu di VACUUM FULL - chjude a tavola durante l'operazione.

squadra REINDICE simile à i dui precedenti, ma ricustruisce un indice specificu o tutti l'indici di a tabella. I chjusi sò ligeramente più debuli: ShareLock nantu à a tavula (impedisce mudificazioni, ma permette di selezziunà) è AccessExclusiveLock nantu à l'indici chì hè ricustruitu (blocca e dumande cù questu indice). In ogni casu, in a 12a versione di Postgres apparsu un paràmetru CONCURRENTLY, chì permette di ricustruisce l'indici senza bluccà l'aghjunzione, a mudificazione o l'eliminazione simultanea di i registri.

In versioni precedenti di Postgres, pudete ottene un risultatu simili à REINDEX CONCURRENTLY usendu CREATE INDEX CONCURRENTLY. Permette di creà un indexu senza strettu chjusu (ShareUpdateExclusiveLock, chì ùn interferiscenu micca cù e dumande parallele), poi rimpiazzà l'indici vechju cù un novu è sguassate u vechju indice. Questu permette di eliminà index bloat senza interferiscenu cù a vostra applicazione. Hè impurtante di cunsiderà chì quandu si ricustruisce l'indici, ci sarà una carica supplementu nantu à u sottosistema di discu.

Cusì, se per l'indici ci sò modi per eliminà bloat "à a mosca", allora ùn ci hè nimu per i tavulini. Questu hè induve diverse estensioni esterne entranu in ghjocu: pg_repack (ex pg_reorg), pgcompact, pgcompacttable è altri. In questu articulu, ùn li paragunaraghju micca è parleraghju solu di pg_repack, chì, dopu qualchì mudificazione, avemu aduprà noi stessi.

Cumu funziona pg_repack

Postgres: bloat, pg_repack è limitazioni differite
Diciamu chì avemu un tavulinu cumpletamente ordinariu - cù indici, restrizioni è, sfurtunatamenti, cù bloat. U primu passu di pg_repack hè di creà una tabella di log per almacenà e dati nantu à tutti i cambiamenti mentre hè in esecuzione. U trigger riplicherà questi cambiamenti per ogni inserimentu, aghjurnà è sguassà. Allora una tavola hè creata, simile à l'uriginale in struttura, ma senza indici è restrizioni, per ùn rallentà u prucessu di inserimentu di dati.

In seguitu, pg_repack trasferisce i dati da a vechja tavola à a nova tavola, filtrà automaticamente tutte e fila irrilevanti, è poi crea indici per a nova tavola. Durante l'esekzione di tutte queste operazioni, i cambiamenti s'accumulanu in a tavola di log.

U prossimu passu hè di trasfiriri i cambiamenti à a nova tavula. A migrazione hè realizata annantu à parechje iterazioni, è quandu ci sò menu di 20 entrate in a tavula di log, pg_repack acquista un forte serratura, migra l'ultimi dati, è rimpiazza a vechja tavola cù a nova in i tavulini di u sistema Postgres. Questu hè u solu tempu è assai cortu quandu ùn puderete micca travaglià cù a tavola. Dopu questu, a vechja tavola è a tavula cù logs sò sguassate è u spaziu hè liberatu in u sistema di schedari. U prucessu hè cumpletu.

Tuttu pare bè in teoria, ma chì succede in pratica? Avemu pruvatu pg_repack senza carica è sottu carica, è verificatu u so funziunamentu in casu d'arrestu prematuru (in altre parolle, usendu Ctrl + C). Tutti i testi eranu pusitivi.

Andemu à a tenda di l'alimentariu - è dopu tuttu ùn hè micca andatu cum'è l'aspittavamu.

Prima pancake in vendita

In u primu cluster avemu ricevutu un errore nantu à una violazione di una limitazione unica:

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

Questa limitazione avia un nome generatu automaticamente index_16508 - hè stata creata da pg_repack. Basatu nantu à l'attributi inclusi in a so cumpusizioni, avemu determinatu "a nostra" restrizzione chì currisponde à questu. U prublema hè diventatu chì questu ùn hè micca una limitazione cumplettamente ordinaria, ma una differita (limitazione differita), i.e. a so verificazione hè realizata più tardi da u cumandamentu sql, chì porta à cunsequenze inespettate.

Limitazioni differite: perchè sò necessarii è cumu travaglianu

Un pocu di teoria nantu à e restrizioni differite.
Fighjemu un esempiu simplice: avemu un libru di riferimentu di vitture cù dui attributi - u nome è l'ordine di a vittura in u cartulare.
Postgres: bloat, pg_repack è limitazioni differite

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



Diciamu chì avemu bisognu di scambià a prima è a seconda vittura. A suluzione simplice hè di aghjurnà u primu valore à u sicondu, è u sicondu à u primu:

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

Ma quandu eseguimu stu codice, aspittemu una violazione di limitazione perchè l'ordine di i valori in a tabella hè unicu:

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

Cumu possu fà di manera diversa? Opzione unu: aghjunghje un sustituzione di valore supplementu à un ordine chì hè garantitu chì ùn esiste micca in a tavula, per esempiu "-1". In a prugrammazione, questu hè chjamatu "scambià i valori di dui variàbili attraversu un terzu". L'unicu inconveniente di stu metudu hè l'aghjurnamentu supplementu.

Opzione dui: Redesignate a tavula per utilizà un tipu di dati in virgule flottante per u valore di l'ordine invece di interi. Allora, quandu aghjurnà u valore da 1, per esempiu, à 2.5, a prima entrata automaticamente "stand" trà a seconda è a terza. Sta suluzione travaglia, ma ci sò dui limitazioni. Prima, ùn hà micca travagliatu per voi se u valore hè utilizatu in un locu in l'interfaccia. Siconda, secondu a precisione di u tipu di dati, avete un numeru limitatu di inserimenti pussibuli prima di ricalculari i valori di tutti i registri.

Opzione trè: rende a limitazione differita in modu chì hè verificata solu à u mumentu di l'impegnu:

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

Siccomu a logica di a nostra dumanda iniziale assicura chì tutti i valori sò unichi à u mumentu di l'impegnu, hà da successu.

L'esempiu discutitu sopra hè, sicuru, assai sinteticu, ma revela l'idea. In a nostra applicazione, usemu limitazioni differite per implementà a logica chì hè rispunsevuli di risolve i cunflitti quandu l'utilizatori travaglianu simultaneamente cù oggetti di widget spartuti nantu à u bordu. Utilizà tali restrizioni ci permette di fà u codice di l'applicazione un pocu più simplice.

In generale, secondu u tipu di limitazione, Postgres hà trè livelli di granularità per cuntrollà: livelli di fila, transazzione è espressione.
Postgres: bloat, pg_repack è limitazioni differite
Source: begriffs

CHECK è NOT NULL sò sempre verificati à u livellu di fila; per altre restrizioni, cum'è pò esse vistu da a tavula, ci sò diverse opzioni. Pudete leghje più ccà.

Per riassumere brevemente, e restrizioni differite in una quantità di situazione furnisce un codice più leggibile è menu cumandamenti. In ogni casu, avete da pagà per questu complicà u prucessu di debugging, postu chì u mumentu chì l'errore si trova è u mumentu chì scopre nantu à questu sò separati in u tempu. Un altru prublema pussibule hè chì u pianificatore ùn pò micca sempre esse capace di custruisce un pianu ottimali se a dumanda implica una limitazione differita.

Migliuramentu di pg_repack

Avemu cupertu ciò chì sò e restrizioni differite, ma cumu si sò in relazione cù u nostru prublema? Ricurdemu l'errore chì avemu ricevutu prima:

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

Ci hè quandu e dati sò copiati da una tavola di log à una nova tavola. Questu pare stranu perchè ... i dati in a tavula di logu hè impegnatu inseme cù i dati in a tavola fonte. S'elli satisfacenu e limitazioni di a tavola originale, cumu si ponu violà e listessi limitazioni in u novu?

Comu risulta, a radica di u prublema si trova in u passu precedente di pg_repack, chì crea solu indici, ma micca limitazioni: a vechja tavola hà avutu una limitazione unica, è u novu hà creatu un indici unicu invece.

Postgres: bloat, pg_repack è limitazioni differite

Hè impurtante di nutà quì chì, se a limitazione hè normale è micca differita, allora l'indici unicu creatu invece hè equivalente à sta limitazione, perchè E restrizioni uniche in Postgres sò implementate creendu un indice unicu. Ma in u casu di una limitazione differita, u cumpurtamentu ùn hè micca u listessu, perchè l'indici ùn pò micca esse diferitu è ​​hè sempre verificatu à u mumentu chì u cumandamentu sql hè eseguitu.

Cusì, l'essenza di u prublema si trova in u "ritardu" di a verificazione: in a tavula originale si trova à u mumentu di l'impegnu, è in a nova tavola à u mumentu chì u cumandamentu sql hè eseguitu. Questu significa chì avemu bisognu di assicurà chì i cuntrolli sò realizati u listessu in i dui casi: o sempre ritardati, o sempre subitu.

Allora chì idee avemu avutu ?

Crea un indice simile à deferred

A prima idea hè di fà i dui cuntrolli in modu immediatu. Questu pò generà parechje restrizioni falsi pusitivi, ma s'ellu ci sò pocu di elli, questu ùn deve micca affettà u travagliu di l'utilizatori, postu chì tali cunflitti sò una situazione normale per elli. Accadunu, per esempiu, quandu dui utilizatori cumincianu à edità u stessu widget à u stessu tempu, è u cliente di u sicondu utilizatore ùn hà micca tempu per riceve infurmazione chì u widget hè digià bluccatu per edità da u primu utilizatore. In una tale situazione, u servitore ricusa u sicondu utilizatore, è u so clientu rinfriscà i cambiamenti è bluccà u widget. Un pocu dopu, quandu u primu utilizatore compie l'edità, u sicondu riceverà infurmazione chì u widget ùn hè più bluccatu è puderà ripetiri a so azzione.

Postgres: bloat, pg_repack è limitazioni differite

Per assicurà chì i cuntrolli sò sempre in modalità non-differita, avemu creatu un novu indice simili à a limitazione differita originale:

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

In l'ambiente di prova, avemu ricevutu solu uni pochi d'errori previsti. Successu! Avemu currettu pg_repack di novu nantu à a pruduzzione è avemu 5 errori nantu à u primu cluster in una ora di travagliu. Questu hè un risultatu accettatu. In ogni casu, digià annantu à u sicondu cluster u numeru di errori hà aumentatu significativamente è avemu avutu a piantà pg_repack.

Perchè hè accadutu? A probabilità di un errore dipende da quanti utilizatori travaglianu cù i stessi widgets à u stessu tempu. Apparentemente, in quellu mumentu ci era assai menu cambiamenti cumpetitivi cù i dati guardati nantu à u primu cluster chì in l'altri, i.e. eramu solu "furtunatu".

L'idea ùn hà micca travagliatu. À quellu puntu, avemu vistu duie altre suluzioni: riscrivite u nostru codice di l'applicazione per dispensà di limitazioni differite, o "insegni" pg_repack per travaglià cun elli. Avemu sceltu u sicondu.

Sustituisce l'indici in a nova tavula cù restrizioni differite da a tavola originale

U scopu di a rivisione era evidenti - se a tavula originale hà una limitazione differita, allora per u novu avete bisognu di creà una tale limitazione, è micca un indice.

Per pruvà i nostri cambiamenti, avemu scrittu una prova simplice:

  • tavula cù una limitazione differita è un record;
  • inserisci dati in un ciclu chì cunflitti cù un registru esistente;
  • fate un aghjurnamentu - i dati ùn sò più cunflitti;
  • compie i cambiamenti.

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;

A versione uriginale di pg_repack hà sempre crash in u primu inserimentu, a versione mudificata hà travagliatu senza errori. Perfettu.

Andemu à a pruduzzione è torna un errore in a listessa fase di copia di dati da a tavola di log à una nova:

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

Situazione classica: tuttu funziona in ambienti di prova, ma micca in produzzione ?!

APPLY_COUNT è a junzione di dui lotti

Avemu cuminciatu à analizà u codice littiralmenti linea per linea è scupertu un puntu impurtante: i dati sò trasferiti da a tavola di log à una nova in batch, a constante APPLY_COUNT indicava a dimensione di u batch:

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

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

U prublema hè chì i dati da a transazzione originale, in quale parechje operazioni puderanu violà a limitazione, quandu si trasfirìu, ponu finisce à a junction of two lots - a mità di i cumandamenti seranu impegnati in u primu batch, è l'altra mità. in u sicondu. E quì, secondu a vostra furtuna: se i squadre ùn viulanu nunda in u primu batch, allora tuttu hè bè, ma si facenu, un errore si trova.

APPLY_COUNT hè uguali à 1000 records, chì spiega perchè i nostri testi anu successu - ùn anu micca copre u casu di "junction batch". Avemu usatu dui cumandamenti - inserisce è aghjurnà, cusì esattamente 500 transazzioni di dui cumandamenti sò sempre stati posti in un batch è ùn avemu micca avutu prublemi. Dopu avè aghjustatu a seconda aghjurnazione, a nostra edizione hà cessatu di travaglià:

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;

Allora, u prossimu compitu hè di assicurà chì e dati da a tavula originale, chì hè stata cambiata in una transazzione, finiscinu in a nova tavola ancu in una transazzione.

Rifiuta di batching

È dinò avemu avutu duie suluzioni. Prima: abbandunemu cumplettamente a particione in batch è trasfiremu dati in una transazzione. U vantaghju di sta suluzione era a so simplicità - i cambiamenti di codice necessarii eranu minimi (per via, in versioni più vechje pg_reorg hà travagliatu esattamente cusì). Ma ci hè un prublema - creemu una transazzione di longa durata, è questu, cum'è dettu prima, hè una minaccia per l'emergenza di un novu bloat.

A seconda suluzione hè più cumplessa, ma prubabilmente più curretta: crea una colonna in a tavula di logu cù l'identificatore di a transazzione chì aghjunghjenu dati à a tavula. Allora, quandu copiemu dati, pudemu raggruppà per questu attributu è assicurà chì i cambiamenti cunnessi sò trasferiti inseme. U batch serà furmatu da parechje transazzione (o una grande) è a so dimensione varierà secondu a quantità di dati cambiatu in queste transazzione. Hè impurtante di nutà chì, postu chì e dati da e diverse transazzione entra in a tavola di log in un ordine aleatoriu, ùn serà più pussibule di leghje sequentially, cum'è prima. seqscan per ogni dumanda cù filtru da tx_id hè troppu caru, un indexu hè necessariu, ma ancu rallentà u metudu per via di l'overhead di l'aghjurnà. In generale, cum'è sempre, avete bisognu di sacrificà qualcosa.

Dunque, avemu decisu di principià cù a prima opzione, perchè hè più simplice. Prima, era necessariu di capisce chì una transazzione longa seria un veru prublema. Siccomu u trasferimentu principali di dati da a vechja tavola à a nova si trova ancu in una transazzione longa, a quistione si trasforma in "quantu aumenteremu sta transazzione?" A durata di a prima transazzione dipende principarmenti da a dimensione di a tavula. A durata di una nova dipende da quanti cambiamenti s'acumulanu in a tavula durante u trasferimentu di dati, i.e. nantu à l'intensità di a carica. U pg_repack run hè accadutu durante un tempu di carica minima di serviziu, è u voluminu di cambiamenti era sproporzionatamente chjucu cumparatu cù a dimensione originale di a tavola. Avemu decisu chì pudemu trascuratà u tempu di una nova transazzione (per paragunà, in media hè 1 ora è 2-3 minuti).

L'esperimenti eranu pusitivi. Lanciate ancu nantu à a produzzione. Per a chjarità, quì hè una stampa cù a dimensione di una di e basa di dati dopu a esecuzione:

Postgres: bloat, pg_repack è limitazioni differite

Siccomu eramu cumplettamente soddisfatti di sta suluzione, ùn avemu micca pruvatu à implementà a seconda, ma avemu cunsideratu a pussibilità di discutiri cù i sviluppatori di l'estensione. A nostra rivisione attuale, sfurtunatamenti, ùn hè ancu pronta per a publicazione, postu chì solu solu risolve u prublema cù restrizioni differite uniche, è per un patch cumpletu hè necessariu di furnisce un supportu per altri tipi. Speremu di pudè fà questu in u futuru.

Forsi avete una quistione, perchè avemu ancu implicatu in sta storia cù a mudificazione di pg_repack, è ùn hà micca usatu, per esempiu, i so analoghi? À un certu puntu avemu ancu pensatu à questu, ma l'esperienza pusitiva di usà prima, nantu à tavule senza limitazione differita, ci hà motivatu à pruvà à capisce l'essenza di u prublema è risolve. Inoltre, l'utilizazione di altre suluzione richiede ancu u tempu per fà e teste, cusì avemu decisu chì prima pruvemu di risolve u prublema in questu, è se avemu capitu chì ùn pudemu micca fà questu in un tempu raghjone, allora avemu principiatu à circà l'analogi. .

scuperti

Ciò chì pudemu ricumandemu basatu annantu à a nostra sperienza:

  1. Monitorate u vostru bloat. Basatu nantu à i dati di surviglianza, pudete capisce cumu bè l'autovacuum hè cunfiguratu.
  2. Aghjustate AUTOVACUUM per mantene a gonfiatura à un livellu accettabile.
  3. Se u bloat hè sempre in crescita è ùn pudete micca superà aduprendu strumenti fora di a scatula, ùn avete micca paura di utilizà estensioni esterne. A cosa principal hè di pruvà tuttu bè.
  4. Ùn àbbia paura di mudificà e soluzioni esterne per adattà à i vostri bisogni - qualchì volta questu pò esse più efficace è ancu più faciule ch'è cambià u vostru propiu codice.

Source: www.habr.com

Add a comment