Postgres: bloat, pg_repack û astengiyên paşdexistin

Postgres: bloat, pg_repack û astengiyên paşdexistin

Bandora felqê li ser tablo û nîşanan bi berfirehî tê zanîn û ne tenê di Postgres de heye. Rêbaz hene ku meriv bi wê re li derveyî qutiyê mijûl bibe, mîna VACUUM FULL an CLUSTER, lê ew di dema xebatê de tabloyan digirin û ji ber vê yekê her gav nikarin werin bikar anîn.

Gotar dê teoriyek piçûk di derheqê ka bloat çawa çêdibe, hûn çawa dikarin wê şer bikin, li ser astengiyên paşdexistin û pirsgirêkên ku ew di karanîna pêveka pg_repack de derdixin de heye.

Ev gotar li ser bingeha hatiye nivîsandin axaftina min li PgConf.Russia 2020.

Çima felq çêdibe?

Postgres li ser modelek pir-guhertoyek (MVCC). Esasê wê ev e ku her rêzek di tabloyê de dikare çend guhertoyên xwe hebin, di heman demê de danûstendin ji yek ji van guhertoyan zêdetir nabînin, lê ne hewce ne yek yek. Ev dihêle ku çend danûstendin bi hevdemî bixebitin û bi rastî bandorek li ser hevûdu tune.

Eşkere ye ku ev hemî versiyonên pêdivî ye ku bêne hilanîn. Postgres rûpel bi rûpel bi bîranînê re dixebite û rûpelek mîqdara herî hindik a daneyê ye ku dikare ji dîskê were xwendin an were nivîsandin. Werin em li mînakek piçûk binêrin da ku fêm bikin ka ev çawa diqewime.

Em bêjin tabloyek me heye ku me çend tomar lê zêde kirine. Daneyên nû di rûpela yekem a pelê de ku tablo tê de ye derketine. Vana guhertoyên zindî yên rêzan in ku ji bo danûstendinên din ên piştî peywirdarkirinê têne peyda kirin (ji bo sadebûnê, em ê texmîn bikin ku asta veqetandinê Read Committed e).

Postgres: bloat, pg_repack û astengiyên paşdexistin

Dûv re me yek ji navnîşan nûve kir, bi vî rengî guhertoya kevn wekî ku êdî ne têkildar destnîşan kir.

Postgres: bloat, pg_repack û astengiyên paşdexistin

Gav bi gav, nûvekirin û jêbirina guhertoyên rêzê, me bi rûpelek ku tê de bi qasî nîvê daneyan "çopê" ye, bi dawî bû. Ev dane ji bo ti danûstendinê nayê dîtin.

Postgres: bloat, pg_repack û astengiyên paşdexistin

Postgres mekanîzmayek heye VACUUM, ku guhertoyên kevnar paqij dike û cîh ji daneyên nû re vedike. Lê heke ew bi têra xwe bi tundî nehatibe mîheng kirin an di tabloyên din de mijûl be, wê hingê "daneyên çopê" dimîne, û pêdivî ye ku em rûpelên zêde ji bo daneyên nû bikar bînin.

Ji ber vê yekê di mînaka me de, di demek demkî de tablo dê ji çar rûpelan pêk were, lê tenê nîvê wê dê daneyên zindî hebe. Wekî encamek, dema ku bigihîjin tabloyê, em ê ji hewcedariyê bêtir daneyan bixwînin.

Postgres: bloat, pg_repack û astengiyên paşdexistin

Tewra ku VACUUM naha hemî guhertoyên rêzê yên negirêdayî jêbibe, rewş dê bi rengek berbiçav baştir nebe. Em ê di rûpelan de an jî heta tevahiya rûpelan ji bo rêzên nû cîhê belaş hebe, lê em ê dîsa jî ji hewcedariyê bêtir daneyan bixwînin.
Bi awayê, heke rûpelek bi tevahî vala (ya duyemîn di mînaka me de) li dawiya pelê be, wê hingê VACUUM dê bikaribe wê bibire. Lê niha ew di ortê de ye, ji ber vê yekê tiştek bi wê nayê kirin.

Postgres: bloat, pg_repack û astengiyên paşdexistin

Gava ku hejmara rûpelên weha vala an pir kêm mezin dibe, ku jê re bloat tê gotin, ew dest pê dike ku bandorê li performansê bike.

Her tiştê ku li jor hatî destnîşan kirin mekanîzmaya peydabûna felqê di tabloyan de ye. Di indexan de ev bi heman rengî diqewime.

Ma min felq heye?

Gelek rê hene ku hûn diyar bikin ka we felq heye. Fikra ya yekem ev e ku meriv statîstîkên Postgres-ê yên hundurîn bikar bîne, ku di derheqê hejmara rêzên di tabloyan de, hejmara rêzên "zindî" û hwd de agahdariya nêzîk dihewîne. Hûn dikarin li ser Înternetê gelek guhertoyên nivîsarên amade bibînin. Me esas girt nivîs ji Pisporên PostgreSQL, ku dikarin tabloyên bloatê digel pêdekên btree toast û bloat binirxînin. Di ezmûna me de, xeletiya wê 10-20% e.

Rêyek din jî karanîna dirêjkirinê ye pgstattuple, ku destûrê dide te ku hûn li hundurê rûpelan binihêrin û hem nirxek texmînkirî û hem jî nirxek bloatek rastîn bistînin. Lê di doza duyemîn de, hûn ê neçar bibin ku tevahiya tabloyê bişopînin.

Em nirxek piçûkek piçûk, heya 20%, qebûl dikin. Ew dikare wekî analogek dagirtina faktorê were hesibandin maseyên и indexes. Di 50% û jor de, dibe ku pirsgirêkên performansê dest pê bikin.

Rêbazên ji bo têkoşîna li dijî şekir

Postgres çend awayan hene ku meriv bi felqê ji qutiyê re mijûl bibe, lê ew her gav ji bo her kesî ne maqûl in.

AUTOVACUUMê mîheng bikin da ku felq çênebe. An jî rasttir, da ku ew di astek ku ji we re were pejirandin de bimîne. Ev wekî şîreta "kapîtan" xuya dike, lê di rastiyê de ev her gav ne hêsan e ku meriv bigihîje. Mînakî, we bi guhertinên birêkûpêk di şemaya daneyê de pêşkeftinek çalak heye, an celebek koçkirina daneyê pêk tê. Wekî encamek, dibe ku profîla barkirina we pir caran biguhezîne û bi gelemperî ji tabloya tabloyê cûda dibe. Ev tê vê wateyê ku hûn hewce ne ku bi domdarî hinekî pêşde bixebitin û AUTOVACUUM-ê li ser profîla guheztina her tabloyê rast bikin. Lê eşkere ye ku ev ne hêsan e.

Sedemek din a hevpar ku çima AUTOVACUUM nikare bi tabloyan bidome ev e ji ber ku danûstandinên demdirêj hene ku pêşî li paqijkirina daneya ku ji wan danûstendinan re heye nahêle. Pêşniyara li vir jî eşkere ye - ji danûstendinên "dangdar" xilas bibin û dema danûstendinên çalak kêm bikin. Lê heke barkirina serîlêdana we hîbrîdek OLAP û OLTP be, wê hingê hûn dikarin di heman demê de gelek nûvekirinên pir caran û pirsên kurt, û hem jî operasyonên demdirêj hebin - mînakî, çêkirina raporek. Di rewşek wusa de, hêja ye ku meriv li ser belavkirina barkirinê li ser bingehên cihêreng bifikire, ku dê rê bide ku her yek ji wan hûrgulî çêbike.

Mînakek din - her çend profîl homojen be, lê databas di bin barek pir zêde de ye, wê hingê dibe ku AUTOVACUUM-a herî êrîşkar jî bi ser nekeve, û felq dê çêbibe. Scaling (vertical an horizontal) tenê çareserî ye.

Di rewşek ku we AUTOVACUUM saz kiriye de çi bikin, lê bloat her ku diçe mezin dibe.

tîma VACUUM FULL naveroka tablo û nîşaneyan ji nû ve ava dike û tenê daneyên têkildar di wan de dihêle. Ji bo rakirina blotê, ew bi rengek bêkêmasî dixebite, lê di dema darvekirina wê de kilîtek taybetî ya li ser masê tê girtin (AccessExclusiveLock), ku dê nehêle ku lêpirsînên li ser vê tabloyê werin bicîh kirin, tewra jî hildibijêre. Ger hûn dikarin karûbarê xwe an beşek ji wê ji bo demekê rawestînin (ji deh hûrdeman heya çend demjimêran li gorî mezinahiya databasê û hardware xwe ve girêdayî ye), wê hingê ev vebijark çêtirîn e. Mixabin, dema me tune ku em VACUUM FULL di dema lênihêrîna plansazkirî de bimeşînin, ji ber vê yekê ev rêbaz ji me re ne maqûl e.

tîma PIRS Naveroka tabloyan bi heman awayê VACUUM FULL ji nû ve ava dike, lê dihêle hûn pêvekek diyar bikin ku li gorî wê dê dane bi fizîkî li ser dîskê werin rêz kirin (lê di pêşerojê de rêzik ji bo rêzên nû nayê garantî kirin). Di hin rewşan de, ev ji bo hejmarek pirsan xweşbîniyek baş e - digel xwendina gelek tomaran ji hêla index. Kêmasiya fermanê wekî ya VACUUM FULL e - di dema xebatê de maseyê kilît dike.

tîma REINDEX mîna her du yên berê, lê pêdekek taybetî an hemî navnîşên tabloyê ji nû ve ava dike. Girtî hinekî qels in: ShareLock li ser sifrê (guhertinan asteng dike, lê destûrê dide hilbijartinê) û AccessExclusiveLock li ser navnîşa ku ji nû ve hatî çêkirin (pirsan bi karanîna vê pêvekê asteng dike). Lêbelê, di guhertoya 12-ê ya Postgres de pîvanek xuya bû HEVKARÎ, ku destûrê dide te ku hûn îndeksê ji nû ve ava bikin bêyî ku lêzêdekirin, guhertin an jêbirina tomarên hevdemî asteng bikin.

Di guhertoyên berê yên Postgres de, hûn dikarin encamek mîna REINDEX-ê bi hev re bikar bînin bi dest bixin. BİXWÎNE BİXWÎNE BİXWÎNE BİXWÎNE. Ew dihêle hûn pêvekek bêyî girtina hişk biafirînin (ShareUpdateExclusiveLock, ku bi pirsên paralel re mudaxele nake), dûv re pêveka kevin bi ya nû biguhezînin û pêveka kevn jêbirin. Ev destûrê dide te ku bêyî ku destwerdana serîlêdana xwe bike bloatê indexê ji holê rake. Girîng e ku meriv bihesibîne ku dema ji nû ve avakirina indexan dê li ser binepergala dîskê barek zêde hebe.

Bi vî rengî, heke ji bo îndeksan rêyên ji holê rakirina felqê "li ser firînê" hebin, wê hingê ji bo tabloyan tune. Li vir e ku cûrbecûr dirêjkirinên derveyî têne lîstin: pg_repack (berê pg_reorg), pgcompact, pgcompactable û yên din. Di vê gotarê de, ez ê wan hevber nekim û tenê li ser pg_repack, ku piştî hin guhertinan, em bixwe bikar tînin biaxivim.

Pg_repack çawa dixebite

Postgres: bloat, pg_repack û astengiyên paşdexistin
Ka em bibêjin tabloyek me ya bi tevahî asayî heye - bi îndeks, sînorkirin û, mixabin, bi felq. Pêngava yekem a pg_repack ev e ku meriv tabloyek têketinê biafirîne ku dema ku ew dimeşe daneyên di derheqê hemî guhertinan de hilîne. Tetik dê van guhertinan ji bo her têketin, nûvekirin û jêbirinê dubare bike. Dûv re tabloyek tê çêkirin, di strukturê de mîna ya orîjînal, lê bê index û sînordar, ji bo ku pêvajoya têxistina daneyan hêdî neke.

Dûv re, pg_repack daneyan ji tabloya kevin vediguhezîne tabloya nû, bixweber hemî rêzên negirêdayî fîlter dike, û dûv re ji bo tabloya nû indexan diafirîne. Di dema pêkanîna van hemî operasyonan de, guhertin di tabloya têketinê de kom dibin.

Pêngava paşîn ev e ku guhartinan veguhezîne tabloya nû. Koçberî li ser çend dubareyan pêk tê, û gava ku di tabloya têketinê de ji 20 navnîşan kêmtir mabin, pg_repack kilîtkirinek bihêz digire, daneyên herî dawî koç dike û di tabloyên pergala Postgres de tabloya kevn bi ya nû diguhezîne. Dema ku hûn ê nikaribin bi sifrê re bixebitin ev demek tenê û pir kurt e. Piştî vê yekê, tabloya kevn û tabloya bi têketin têne jêbirin û cîh di pergala pelan de azad dibe. Pêvajo temam bûye.

Her tişt di teoriyê de pir xweş xuya dike, lê di pratîkê de çi dibe? Me pg_repack bê bar û di bin barkirinê de ceriband, û di rewşa rawestana zû de xebata wê kontrol kir (bi gotinek din, bi karanîna Ctrl+C). Hemû test erênî bûn.

Em çûn firotgeha xwarinê - û paşê her tişt wekî ku me hêvî dikir neçû.

Pancake yekem li firotanê

Di koma yekem de me xeletiyek derbarê binpêkirina astengiyek bêhempa wergirt:

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

Vê tixûbê navek index_16508-a ku bixweber hatî çêkirin hebû - ew ji hêla pg_repack ve hatî çêkirin. Li ser bingeha taybetmendiyên ku di pêkhateya wê de cih digirin, me astengiya "me" ya ku pê re têkildar e destnîşan kir. Pirsgirêk derket holê ku ev ne sînorkirinek bi tevahî asayî ye, lê yek paşverû ye (astengiya taloqkirî), ango. verastkirina wê ji fermana sql dereng tê kirin, ku dibe sedema encamên nediyar.

Astengiyên paşdexistin: çima ew hewce ne û ew çawa dixebitin

Teoriyek piçûk di derbarê qedexeyên paşdexistî de.
Ka em mînakek hêsan bifikirin: me pirtûkek sifrê-referansê ya gerîdeyan bi du taybetmendiyan heye - nav û rêza gerîdeyê di pelrêçê de.
Postgres: bloat, pg_repack û astengiyên paşdexistin

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



Ka em bibêjin ku me hewce bû ku otomobîlên yekem û duyemîn biguhezînin. Çareseriya rast ev e ku nirxa yekem bi ya duyemîn, û ya duyemîn jî ji ya yekem nûve bike:

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

Lê gava ku em vê kodê dimeşînin, em li bendê ne ku binpêkirinek sînordar be ji ber ku rêza nirxên di tabloyê de bêhempa ye:

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

Ez çawa dikarim wê cuda bikim? Vebijêrk yek: guheztinek nirxek zêde li fermanek ku garantî ye ku di tabloyê de tune be zêde bike, mînakî "-1". Di bernamekirinê de, ji vê re "veguheztina nirxên du guherbaran bi riya sêyemîn" tê gotin. Tenê kêmasiya vê rêbazê nûvekirina zêde ye.

Vebijarka dudu: Tabloyê ji nû ve dîzayn bikin da ku ji bo nirxa fermanê li şûna hejmarên tev de celebek daneya niqteya herikîn bikar bînin. Dûv re, dema ku nirxa ji 1-ê, mînakî, berbi 2.5-ê nûve bike, têketina yekem bixwe dê di navbera ya duyemîn û sêyemîn de "raweste". Ev çareserî dixebite, lê du sînor hene. Ya yekem, ew ê ji we re nexebite ger nirx li cîhek navberê were bikar anîn. Ya duyemîn, li gorî rastbûna celebê daneyê, berî ku hûn nirxên hemî tomaran ji nû ve bijmêrin, hûn ê hejmarek hindik têkelên gengaz hebin.

Vebijarka sêyem: astengiyê bi paş de bihêlin da ku ew tenê di dema bicîhkirinê de were kontrol kirin:

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

Ji ber ku mantiqa daxwaza meya destpêkê piştrast dike ku hemî nirx di dema kirinê de bêhempa ne, ew ê biserkeve.

Mînaka ku li jor hatî nîqaş kirin, bê guman, pir sentetîk e, lê ew ramanê eşkere dike. Di serîlêdana xwe de, em astengên paşverû bikar tînin da ku mentiqê ku berpirsiyarê çareserkirina nakokiyan e dema ku bikarhêner bi hevdemî bi hêmanên widgetên hevpar ên li ser panelê re dixebitin, bikar tînin. Bikaranîna qedexeyên weha dihêle ku em koda serîlêdanê hinekî hêsan bikin.

Bi gelemperî, li gorî celebê astengiyê, Postgres ji bo kontrolkirina wan sê astên hûrgelê hene: rêz, danûstendin, û astên vegotinê.
Postgres: bloat, pg_repack û astengiyên paşdexistin
Source: begriffs

CHECK û NOT NULL her gav di asta rêzê de têne kontrol kirin; ji bo qedexeyên din, wekî ku ji tabloyê tê dîtin, vebijarkên cihêreng hene. Hûn dikarin bêtir bixwînin vir.

Bi kurtasî kurtasî, di gelek rewşan de astengiyên paşdemayî kodek bêtir xwendin û kêmtir ferman peyda dikin. Lêbelê, hûn neçar in ku ji bo vê yekê bi tevlihevkirina pêvajoya xeletkirinê bidin, ji ber ku gava ku xelet çêdibe û gava ku hûn pê dizanin di wextê de têne veqetandin. Pirsgirêkek din a mimkun ev e ku plansaz her gav nekare plansaziyek çêtirîn çêbike heke daxwazek astengiyek paşvexistî hebe.

Başkirina pg_repack

Me veşartiye ku çi astengên paşdemayî ne, lê ew çawa bi pirsgirêka me re têkildar in? Ka em xeletiya ku me berê wergirtî bi bîr bînin:

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

Dema ku dane ji tabloyek têketinê li tabloyek nû tê kopî kirin çêdibe. Ev xerîb xuya dike ji ber ku ... Daneyên di tabloya têketinê de ligel daneyên di tabloya çavkaniyê de têne bicîh kirin. Ger ew astengên tabloya orîjînal têr bikin, ew çawa dikarin heman astengan di tabloya nû de binpê bikin?

Wekî ku derdikeve holê, koka pirsgirêkê di gava berê ya pg_repack de ye, ku tenê pêvekan diafirîne, lê ne astengan: tabloya kevin xwedan astengiyek bêhempa bû, û ya nû li şûna wê navnîşek bêhempa çêkir.

Postgres: bloat, pg_repack û astengiyên paşdexistin

Girîng e ku li vir were zanîn ku heke astengî normal be û neyê paşxistin, wê hingê navnîşa yekta ya ku li şûna wê hatî afirandin bi vê astengiyê re wekhev e, ji ber ku Astengiyên bêhempa yên di Postgres de bi afirandina pêdekek bêhempa têne bicîh kirin. Lê di rewşek astengiyek paşverû de, tevger ne yek e, ji ber ku index nayê paşve xistin û her gav di dema ku emrê sql tête bicîh kirin de tê kontrol kirin.

Ji ber vê yekê, cewhera pirsgirêkê di "derengiya" kontrolê de ye: di tabloya orîjînal de ew di dema danînê de çêdibe, û di tabloya nû de dema ku fermana sql tête darve kirin. Ev tê vê wateyê ku divê em pê ewle bin ku kontrol di her du rewşan de yekane têne kirin: an her gav dereng, an her gav tavilê.

Îcar çi fikrên me hebûn?

Indeksek mîna ya paşvekirî biafirînin

Fikra yekem ev e ku meriv her du kontrolan di moda bilez de pêk bîne. Dibe ku ev çend qedexeyên erênî yên derewîn çêbike, lê heke hindik ji wan hebin, divê ev bandorê li xebata bikarhêneran neke, ji ber ku nakokiyên weha ji bo wan rewşek normal in. Mînakî, ew diqewimin dema ku du bikarhêner di heman demê de dest bi guherandina heman widgetê dikin, û xerîdarê bikarhênerê duyemîn wext tune ku agahdarî werbigire ku widget jixwe ji bo guherandinê ji hêla bikarhênerê yekem ve hatî asteng kirin. Di rewşek wusa de, server bikarhênerê duyemîn red dike, û muwekîlê wê guhertinan paşde vedigerîne û widgetê asteng dike. Dûv re, gava ku bikarhênerê yekem guherandinê biqedîne, ya duyemîn dê agahdarî werbigire ku widget êdî nayê asteng kirin û dê karibe çalakiya xwe dubare bike.

Postgres: bloat, pg_repack û astengiyên paşdexistin

Ji bo ku bicîh bikin ku kontrol her gav di moda ne-paşvekirî de ne, me navnîşek nû ya mîna astengiya paşvekirî ya orjînal çêkir:

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

Di hawîrdora ceribandinê de, me tenê çend xeletiyên hêvîdar wergirtin. Serketinî! Me pg_repack dîsa li ser hilberandinê kir û di saetek xebatê de 5 xeletî li koma yekem girtin. Ev encamek meqbûl e. Lêbelê, jixwe di koma duyemîn de hejmara xeletiyan pir zêde bû û neçar ma ku pg_repack rawestîne.

Çima çêbû? Îhtîmala ku xeletiyek çêbibe girêdayî ye ka çend bikarhêner di heman demê de bi heman widgetan re dixebitin. Xuya ye, di wê gavê de bi daneyên ku li koma yekem hatî hilanîn ji yên din re gelek kêmtir guhertinên pêşbaziyê hebûn, yanî. em tenê "bext" bûn.

Fikir bi ser neket. Di wê nuqteyê de, me du çareseriyên din dîtin: koda serîlêdana xwe ji nû ve binivîsin da ku astengên paşdemayî nehêlin, an "hîn bikin" pg_repack ku bi wan re bixebite. Me ya duyemîn hilbijart.

Indeksên di tabloya nû de bi astengên paşverû yên ji tabloya orîjînal veguherînin

Armanca guheztinê diyar bû - heke tabloya orîjînal xwedan astengiyek paşverû ye, wê hingê ji bo ya nû hûn hewce ne ku astengiyek wusa biafirînin, û ne indexek.

Ji bo ceribandina guhertinên me, me ceribandinek hêsan nivîsî:

  • tabloya bi astengiya paşverû û yek tomar;
  • daneyan têxe nav pêleka ku bi tomarek heyî re nakokî dike;
  • nûvekirinek bikin - dane êdî nakokî;
  • guhertinan pêk bînin.

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;

Guhertoya orîjînal a pg_repack her gav di navnîşa yekem de têk çû, guhertoya hatî guherandin bêyî xeletî xebitî. Ecêb.

Em diçin hilberînê û dîsa di heman qonaxa kopîkirina daneyan ji tabloya têketinê ya nû de xeletiyek distînin:

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

Rewşa klasîk: her tişt di hawîrdorên ceribandinê de dixebite, lê ne di hilberînê de?!

APPLY_COUNT û girêdana du koman

Me dest bi analîzkirina kodê bi rastî rêz bi xêz kir û xalek girîng kifş kir: dane ji tabloya têketinê vediguhezînin tabloyek nû bi koman, berdewamiya APPLY_COUNT mezinahiya komê destnîşan kir:

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

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

Pirsgirêk ev e ku daneyên ji danûstendina orîjînal, ku tê de çend operasyon dikarin bi potansiyel astengiyê binpê bikin, dema ku têne veguheztin, dikarin li hevbera du beşan biqedin - nîvê fermanan dê di koma yekem de bêne bicîh kirin, û nîvê din. di ya duyem de. Û li vir, bi bextê we ve girêdayî ye: heke tîm di koma yekem de tiştek binpê nekin, wê hingê her tişt baş e, lê heke ew bikin, xeletiyek çêdibe.

APPLY_COUNT bi 1000 qeydan re wekhev e, ku rave dike ka çima ceribandinên me serketî bûn - wan doza "hevbendiya hevî" venegirt. Me du ferman bikar anîn - têxin û nûve bikin, ji ber vê yekê tam 500 danûstendinên du fermanan her gav di komekê de hatin danîn û me tu pirsgirêk nedît. Piştî lêzêdekirina nûvekirina duyemîn, guherandina me rawestiya:

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;

Ji ber vê yekê, peywira din ev e ku meriv pê ewle bibe ku daneyên ji tabloya orîjînal, ku di yek danûstendinê de hate guheztin, di tabloya nû de jî di nav yek danûstendinê de biqede.

Rakirina ji hevgirtinê

Û dîsa du çareyên me hebûn. Pêşîn: bila em bi tevahî dev ji dabeşkirina koman berdin û daneyan di yek danûstendinê de veguhezînin. Feydeya vê çareseriyê sadebûna wê bû - guheztinên kodê yên pêwîst hindik bûn (bi awayê, di guhertoyên kevn de pg_reorg tam wusa dixebitî). Lê pirsgirêkek heye - em danûstendinek demdirêj diafirînin, û ev, wekî ku berê hate gotin, xetereyek e ji bo derketina felqek nû.

Çareseriya duyemîn tevlihevtir e, lê dibe ku rasttir e: di tabloya têketinê de stûnek bi nasnameya danûstendinê ya ku daneyan li tabloyê zêde kiriye biafirînin. Dûv re, gava ku em daneyan kopî dikin, em dikarin wê li gorî vê taybetmendiyê kom bikin û piştrast bikin ku guhertinên têkildar bi hev re têne veguheztin. Berhev dê ji çend danûstendinan (an yek mezinek) pêk were û mezinahiya wê dê li gorî ka çiqas dane di van danûstendinan de hatine guheztin cûda bibe. Girîng e ku bala xwe bidinê ku ji ber ku daneyên ji danûstendinên cihêreng bi rêzek rasthatî têkeve tabloya têketinê, dê êdî ne gengaz be ku ew bi rêzdarî were xwendin, wekî berê. seqscan ji bo her daxwazek bi fîlterkirin ji hêla tx_id ve pir biha ye, pêvekek pêdivî ye, lê ew ê di heman demê de ji ber giraniya nûvekirina wê rêbazê jî hêdî bike. Bi gelemperî, wekî her gav, hûn hewce ne ku tiştek qurban bikin.

Ji ber vê yekê, me biryar da ku em bi vebijarka yekem dest pê bikin, ji ber ku ew hêsantir e. Pêşîn, pêdivî bû ku meriv fêm bike ka danûstendinek dirêj dê pirsgirêkek rastîn be. Ji ber ku veguheztina sereke ya daneyan ji tabloya kevn bo ya nû jî di yek danûstendinek dirêj de pêk tê, pirs veguherî "em ê çiqas vê danûstendinê zêde bikin?" Demjimêra danûstendina yekem bi giranî bi mezinahiya tabloyê ve girêdayî ye. Demjimêra nû ve girêdayî ye ku di dema veguheztina daneyê de çend guhertin di tabloyê de kom dibin, ango. li ser tundiya barkirinê. Rêvekirina pg_repack di dema barkirina karûbarê hindiktirîn de pêk hat, û qebareya guherînan li gorî mezinahiya orîjînal a tabloyê bi rengek nehevseng piçûk bû. Me biryar da ku em dikarin dema danûstendinek nû paşguh bikin (ji bo berhevdanê, bi gelemperî ew 1 demjimêr û 2-3 hûrdem e).

Ceribandinên erênî bûn. Di hilberînê de jî dest pê bikin. Ji bo zelaliyê, li vir wêneyek bi mezinahiya yek ji databasên piştî xebitandinê heye:

Postgres: bloat, pg_repack û astengiyên paşdexistin

Ji ber ku em bi tevahî ji vê çareseriyê razî bûn, me hewl neda ku ya duyemîn bicîh bînin, lê em îhtîmala nîqaşkirina wê bi pêşdebirên dirêjkirinê re dinirxînin. Guhertoya meya heyî, mixabin, hîn ji bo weşanê ne amade ye, ji ber ku me pirsgirêk tenê bi tixûbên taloqkirî yên bêhempa çareser kir, û ji bo pêvekek bêkêmasî pêdivî ye ku piştgirî ji cûreyên din re peyda bikin. Em hêvîdar in ku di paşerojê de vê yekê bikin.

Dibe ku pirsek we hebe, çima em bi guheztina pg_repack jî tevlî vê çîrokê bûn, û mînakî, analogên wê bikar neanîn? Demekê em jî li ser vê yekê fikirîn, lê ezmûna erênî ya karanîna wê berê, li ser tabloyên bêyî astengên paşdemayî, me motîve kir ku em hewl bidin ku cewhera pirsgirêkê fam bikin û wê rast bikin. Wekî din, karanîna çareseriyên din jî ji bo pêkanîna ceribandinan dem hewce dike, ji ber vê yekê me biryar da ku em ê pêşî hewl bidin ku pirsgirêkê di wê de çareser bikin, û heke me fêm kir ku em nikanin vê yekê di demek maqûl de bikin, wê hingê em ê dest bi lênihêrîna analogan bikin. .

vebiguherin

Tiştê ku em dikarin li ser bingeha ezmûna xwe pêşniyar bikin:

  1. Bûka xwe bişopînin. Li ser bingeha daneyên çavdêriyê, hûn dikarin fêm bikin ka otovacuum çiqasî xweş tê mîheng kirin.
  2. AUTOVACUUM-ê eyar bikin da ku bloat di astek pejirandî de bimîne.
  3. Ger felq hîn jî mezin dibe û hûn nikaribin bi karanîna amûrên derveyî qutiyê bi ser bixin, ji karanîna pêvekên derveyî netirsin. Ya sereke ev e ku meriv her tiştî baş biceribîne.
  4. Netirsin ku çareseriyên derveyî li gorî hewcedariyên we biguhezînin - carinan ev dikare ji guheztina koda xwe bi bandortir û hêj hêsantir be.

Source: www.habr.com

Add a comment