Postgres: bloat, pg_repack u restrizzjonijiet differiti

Postgres: bloat, pg_repack u restrizzjonijiet differiti

L-effett tal-bloat fuq it-tabelli u l-indiċi huwa magħruf ħafna u huwa preżenti mhux biss f'Postgres. Hemm modi kif tittrattaha barra mill-kaxxa, bħal VACUUM FULL jew CLUSTER, iżda jissakkru t-tabelli waqt it-tħaddim u għalhekk ma jistgħux dejjem jintużaw.

L-artiklu se jkun fih ftit teorija dwar kif isseħħ in-nefħa, kif tista 'tiġġieledha, dwar restrizzjonijiet differiti u l-problemi li jġibu għall-użu tal-estensjoni pg_repack.

Dan l-artikolu huwa miktub ibbażat fuq id-diskors tiegħi fil-PgConf.Russia 2020.

Għaliex iseħħ nefħa?

Postgres huwa bbażat fuq mudell multi-verżjoni (MVCC). L-essenza tagħha hija li kull ringiela fit-tabella jista 'jkollha diversi verżjonijiet, filwaqt li t-tranżazzjonijiet ma jarawx aktar minn waħda minn dawn il-verżjonijiet, iżda mhux neċessarjament l-istess waħda. Dan jippermetti li diversi tranżazzjonijiet jaħdmu simultanjament u prattikament ma jkollhom l-ebda impatt fuq xulxin.

Ovvjament, dawn il-verżjonijiet kollha jeħtieġ li jinħażnu. Postgres jaħdem bil-memorja paġna b'paġna u paġna hija l-ammont minimu ta 'dejta li tista' tinqara minn disk jew miktuba. Ejja nħarsu lejn eżempju żgħir biex nifhmu kif jiġri dan.

Ejja ngħidu li għandna tabella li magħha żidna diversi rekords. Data ġdida dehret fl-ewwel paġna tal-fajl fejn hija maħżuna t-tabella. Dawn huma verżjonijiet ħajjin ta 'ringieli li huma disponibbli għal tranżazzjonijiet oħra wara impenn (għal sempliċità, se nassumu li l-livell ta' iżolament huwa Read Committed).

Postgres: bloat, pg_repack u restrizzjonijiet differiti

Imbagħad aġġornajna waħda mill-entrati, u b'hekk immarkaw il-verżjoni l-antika bħala li m'għadhiex rilevanti.

Postgres: bloat, pg_repack u restrizzjonijiet differiti

Pass pass, aġġornaw u nħassru verżjonijiet ta 'ringieli, spiċċajna b'paġna li fiha madwar nofs id-dejta hija "żibel". Din id-dejta mhix viżibbli għall-ebda transazzjoni.

Postgres: bloat, pg_repack u restrizzjonijiet differiti

Postgres għandu mekkaniżmu Vakwu, li tnaddaf verżjonijiet skaduti u tagħmel spazju għal data ġdida. Imma jekk ma tkunx ikkonfigurata b'mod aggressiv biżżejjed jew tkun okkupata taħdem f'tabelli oħra, allura "dejta taż-żibel" tibqa ', u rridu nużaw paġni addizzjonali għal dejta ġdida.

Allura fl-eżempju tagħna, f'xi punt fiż-żmien it-tabella se tikkonsisti f'erba 'paġni, iżda nofsha biss se jkun fiha dejta diretta. Bħala riżultat, meta naċċessaw it-tabella, se naqraw ħafna aktar dejta milli meħtieġ.

Postgres: bloat, pg_repack u restrizzjonijiet differiti

Anke jekk VACUUM issa tħassar il-verżjonijiet kollha ta 'ringiela irrilevanti, is-sitwazzjoni mhux se titjieb b'mod drammatiku. Se jkollna spazju ħieles f'paġni jew saħansitra paġni sħaħ għal ringieli ġodda, iżda xorta se nkunu qed naqraw aktar dejta milli meħtieġ.
Mill-mod, jekk paġna kompletament vojta (it-tieni waħda fl-eżempju tagħna) kienet fl-aħħar tal-fajl, allura VACUUM ikun jista 'jittrimmjaha. Imma issa tinsab fin-nofs, allura xejn ma jista’ jsir magħha.

Postgres: bloat, pg_repack u restrizzjonijiet differiti

Meta n-numru ta 'paġni vojta jew skarsi ħafna bħal dawn isir kbir, li jissejjaħ nefħa, jibda jaffettwa l-prestazzjoni.

Kollox deskritt hawn fuq huwa l-mekkaniżmi ta 'l-okkorrenza ta' nefħa fit-tabelli. Fl-indiċi dan jiġri bl-istess mod.

Għandi nefħa?

Hemm diversi modi biex tiddetermina jekk għandekx nefħa. L-idea ta 'l-ewwel hija li tuża statistika interna ta' Postgres, li fiha informazzjoni approssimattiva dwar in-numru ta 'ringieli fit-tabelli, in-numru ta' ringieli "ħaj", eċċ. Tista 'ssib ħafna varjazzjonijiet ta' skripts lesti fuq l-Internet. Ħadna bħala bażi iskrittura minn Esperti PostgreSQL, li jistgħu jevalwaw it-tabelli tal-bloat flimkien ma 'indiċi btree toast u bloat. Fl-esperjenza tagħna, l-iżball tiegħu huwa 10-20%.

Mod ieħor huwa li tuża l-estensjoni pgstattuple, li jippermettilek li tħares ġewwa l-paġni u tikseb kemm valur stmat kif ukoll eżatt. Iżda fit-tieni każ, ser ikollok tiskennja t-tabella kollha.

Aħna nqisu valur żgħir ta 'nefħa, sa 20%, aċċettabbli. Jista 'jitqies bħala analogu ta' fillfactor għal imwejjed и indiċi. F'50% u aktar, jistgħu jibdew problemi ta 'prestazzjoni.

Modi biex tiġi miġġielda n-nefħa

Postgres għandu diversi modi biex jittratta n-nefħa barra mill-kaxxa, iżda mhux dejjem huma adattati għal kulħadd.

Ikkonfigura l-AUTOVACUUM sabiex ma sseħħx nefħa. Jew b'mod aktar preċiż, biex iżżommha f'livell aċċettabbli għalik. Dan jidher qisu parir tal-"kaptan", iżda fir-realtà dan mhux dejjem faċli li jinkiseb. Pereżempju, għandek żvilupp attiv b'bidliet regolari fl-iskema tad-dejta, jew qed isseħħ xi tip ta' migrazzjoni tad-dejta. Bħala riżultat, il-profil tat-tagħbija tiegħek jista 'jinbidel ta' spiss u tipikament ivarja minn tabella għal mejda. Dan ifisser li għandek bżonn taħdem kontinwament ftit 'il quddiem u taġġusta AUTOVACUUM għall-profil li qed jinbidel ta' kull tabella. Imma ovvjament dan mhux faċli li tagħmel.

Raġuni komuni oħra għaliex AUTOVACUUM ma jistax ilaħħaq mat-tabelli hija minħabba li hemm tranżazzjonijiet fit-tul li jipprevjenuh milli tnaddaf id-dejta li hija disponibbli għal dawk it-tranżazzjonijiet. Ir-rakkomandazzjoni hawnhekk hija wkoll ovvja - teħles mit-tranżazzjonijiet "dangling" u timminimizza l-ħin tat-tranżazzjonijiet attivi. Imma jekk it-tagħbija fuq l-applikazzjoni tiegħek hija ibrida ta 'OLAP u OLTP, allura jista' fl-istess ħin ikollok ħafna aġġornamenti frekwenti u mistoqsijiet qosra, kif ukoll operazzjonijiet fit-tul - pereżempju, tibni rapport. F'sitwazzjoni bħal din, ta 'min wieħed jaħseb dwar it-tixrid tat-tagħbija fuq bażijiet differenti, li se jippermetti aktar irfinar ta' kull wieħed minnhom.

Eżempju ieħor - anki jekk il-profil huwa omoġenju, iżda d-database hija taħt tagħbija għolja ħafna, allura anke l-AUTOVACUUM l-aktar aggressiv jista 'ma jlaħħaqx, u se jseħħ nefħa. L-iskala (vertikali jew orizzontali) hija l-unika soluzzjoni.

X'għandek tagħmel f'sitwazzjoni fejn waqqaft AUTOVACUUM, iżda n-nefħa tkompli tikber.

Team VACUUM SĦIĦA jibni mill-ġdid il-kontenut tat-tabelli u l-indiċi u jħalli biss dejta rilevanti fihom. Biex telimina n-nefħa, taħdem perfettament, iżda matul l-eżekuzzjoni tagħha tinqabad lock esklussiv fuq il-mejda (AccessExclusiveLock), li mhux se jippermetti li tesegwixxi mistoqsijiet fuq din il-mejda, anke tagħżel. Jekk tistax taffordja li twaqqaf is-servizz tiegħek jew parti minnu għal xi żmien (minn għexieren ta 'minuti sa diversi sigħat skont id-daqs tad-database u l-hardware tiegħek), allura din l-għażla hija l-aħjar. Sfortunatament, m'għandniex ħin biex inħaddmu VACUUM FULL matul il-manutenzjoni skedata, għalhekk dan il-metodu mhuwiex adattat għalina.

Team GRUPP Jibni mill-ġdid il-kontenut tat-tabelli bl-istess mod bħal VACUUM FULL, iżda jippermettilek li tispeċifika indiċi li skontu d-dejta tkun fiżikament ordnata fuq disk (iżda fil-futur l-ordni mhix garantita għal ringieli ġodda). F'ċerti sitwazzjonijiet, din hija ottimizzazzjoni tajba għal numru ta 'mistoqsijiet - bil-qari ta' rekords multipli skont l-indiċi. L-iżvantaġġ tal-kmand huwa l-istess bħal dak tal-VACUUM FULL - jissakkar il-mejda waqt it-tħaddim.

Team RIINDIĊI simili għat-tnejn ta 'qabel, iżda jerġa' jibni indiċi speċifiku jew l-indiċi kollha tat-tabella. Serraturi huma kemmxejn aktar dgħajfa: ShareLock fuq il-mejda (jipprevjeni modifiki, iżda jippermetti tagħżel) u AccessExclusiveLock fuq l-indiċi li qed jinbena mill-ġdid (imblokka l-mistoqsijiet bl-użu ta 'dan l-indiċi). Madankollu, fit-12-il verżjoni ta 'Postgres deher parametru B'KORRENZA, li jippermettilek tibni mill-ġdid l-indiċi mingħajr ma timblokka ż-żieda, il-modifika jew it-tħassir konkorrenti tar-rekords.

F'verżjonijiet preċedenti ta 'Postgres, tista' tikseb riżultat simili għal REINDEX FIL-KORRENT tuża OĦLOQ INDIĊI FIL-KORRENTI. Jippermettilek toħloq indiċi mingħajr qfil strett (ShareUpdateExclusiveLock, li ma jinterferixxix ma 'mistoqsijiet paralleli), imbagħad ibdel l-indiċi l-antik b'wieħed ġdid u ħassar l-indiċi l-antik. Dan jippermettilek telimina n-nefħa tal-indiċi mingħajr ma tinterferixxi mal-applikazzjoni tiegħek. Huwa importanti li wieħed iqis li meta jerġgħu jinbnew l-indiċi se jkun hemm tagħbija addizzjonali fuq is-subsistema tad-disk.

Għalhekk, jekk għall-indiċi jkun hemm modi kif telimina n-nefħa "fuq il-fly", allura m'hemm xejn għat-tabelli. Dan huwa fejn jidħlu diversi estensjonijiet esterni: pg_repack (qabel pg_reorg), pgcompact, pgcompacttable u oħrajn. F'dan l-artikolu, mhux se nqabbelhom u se nitkellem biss dwar pg_repack, li, wara xi modifika, nużaw lilna nfusna.

Kif jaħdem pg_repack

Postgres: bloat, pg_repack u restrizzjonijiet differiti
Ejja ngħidu li għandna tabella kompletament ordinarja - b'indiċi, restrizzjonijiet u, sfortunatament, b'nefħa. L-ewwel pass ta 'pg_repack huwa li toħloq tabella ta' log biex taħżen data dwar il-bidliet kollha waqt li tkun qed taħdem. Il-grillu se jirreplika dawn il-bidliet għal kull daħħal, aġġornament u tħassar. Imbagħad tinħoloq tabella, simili għal dik oriġinali fl-istruttura, iżda mingħajr indiċi u restrizzjonijiet, sabiex ma jonqosx il-proċess tad-dħul tad-data.

Sussegwentement, pg_repack jittrasferixxi d-dejta mit-tabella l-antika għat-tabella l-ġdida, awtomatikament jiffiltra r-ringieli irrilevanti kollha, u mbagħad joħloq indiċi għat-tabella l-ġdida. Matul l-eżekuzzjoni ta 'dawn l-operazzjonijiet kollha, il-bidliet jakkumulaw fit-tabella tal-log.

Il-pass li jmiss huwa li tittrasferixxi l-bidliet fit-tabella l-ġdida. Il-migrazzjoni titwettaq fuq diversi iterazzjonijiet, u meta jkun fadal inqas minn 20 daħla fit-tabella tal-log, pg_repack jakkwista lock b'saħħtu, jemigra l-aħħar data, u jissostitwixxi t-tabella l-qadima b'dik ġdida fit-tabelli tas-sistema Postgres. Dan huwa l-uniku żmien qasir ħafna meta ma tkunx tista' taħdem mat-tabella. Wara dan, it-tabella l-antika u t-tabella biż-zkuk jitħassru u l-ispazju jinħeles fis-sistema tal-fajls. Il-proċess huwa komplut.

Kollox jidher tajjeb fit-teorija, imma x'jiġri fil-prattika? Aħna ttestjajna pg_repack mingħajr tagħbija u taħt tagħbija, u ċċekkjaw it-tħaddim tiegħu f'każ ta 'waqfien prematur (fi kliem ieħor, bl-użu ta' Ctrl + C). It-testijiet kollha kienu pożittivi.

Morna fil-maħżen tal-ikel - u mbagħad kollox ma marx kif stennejna.

L-ewwel pancake għall-bejgħ

Fuq l-ewwel cluster irċevejna żball dwar ksur ta’ restrizzjoni unika:

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

Din il-limitazzjoni kellha isem ġenerat awtomatikament index_16508 - inħoloq minn pg_repack. Ibbażat fuq l-attributi inklużi fil-kompożizzjoni tiegħu, iddeterminajna r-restrizzjoni "tagħna" li tikkorrispondi għaliha. Il-problema rriżultat li din mhix limitazzjoni kompletament ordinarja, iżda waħda differita (restrizzjoni differita), i.e. il-verifika tiegħu titwettaq aktar tard mill-kmand sql, li jwassal għal konsegwenzi mhux mistennija.

Limitazzjonijiet differiti: għaliex huma meħtieġa u kif jaħdmu

Ftit teorija dwar restrizzjonijiet differiti.
Ejja nikkunsidraw eżempju sempliċi: għandna ktieb ta 'referenza tabella ta' karozzi b'żewġ attributi - l-isem u l-ordni tal-karozza fid-direttorju.
Postgres: bloat, pg_repack u restrizzjonijiet differiti

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



Ejja ngħidu li kellna bżonn nibdlu l-ewwel u t-tieni karozza. Is-soluzzjoni sempliċi hija li taġġorna l-ewwel valur għat-tieni, u t-tieni għall-ewwel:

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

Imma meta nħaddmu dan il-kodiċi, nistennew ksur tar-restrizzjoni minħabba li l-ordni tal-valuri fit-tabella hija unika:

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

Kif nista 'nagħmilha differenti? L-ewwel għażla: żid sostituzzjoni ta’ valur addizzjonali ma’ ordni li hija garantita li ma teżistix fit-tabella, pereżempju “-1”. Fl-ipprogrammar, dan jissejjaħ "skambju tal-valuri ta 'żewġ varjabbli permezz ta' terz." L-uniku żvantaġġ ta 'dan il-metodu huwa l-aġġornament addizzjonali.

Għażla tieni: Iddisinja mill-ġdid it-tabella biex tuża tip ta 'dejta b'punt li jvarja għall-valur tal-ordni minflok interi. Imbagħad, meta taġġorna l-valur minn 1, pereżempju, għal 2.5, l-ewwel dħul awtomatikament "toqgħod" bejn it-tieni u t-tielet. Din is-soluzzjoni taħdem, iżda hemm żewġ limitazzjonijiet. L-ewwel, mhux se jaħdem għalik jekk il-valur jintuża x'imkien fl-interface. It-tieni, skont il-preċiżjoni tat-tip tad-dejta, ser ikollok numru limitat ta 'inserzjonijiet possibbli qabel ma terġa' tikkalkula l-valuri tar-rekords kollha.

It-tielet għażla: agħmel ir-restrizzjoni differita sabiex tiġi ċċekkjata biss fil-ħin tal-impenn:

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

Peress li l-loġika tat-talba inizjali tagħna tiżgura li l-valuri kollha huma uniċi fil-ħin tal-impenn, se tirnexxi.

L-eżempju diskuss hawn fuq huwa, ovvjament, sintetiku ħafna, iżda jiżvela l-idea. Fl-applikazzjoni tagħna, nużaw restrizzjonijiet differiti biex nimplimentaw loġika li hija responsabbli biex issolvi l-kunflitti meta l-utenti jaħdmu simultanjament ma 'oġġetti ta' widget kondiviżi fuq il-bord. L-użu ta 'restrizzjonijiet bħal dawn jippermettilna nagħmlu l-kodiċi tal-applikazzjoni ftit aktar sempliċi.

B'mod ġenerali, skont it-tip ta 'restrizzjoni, Postgres għandu tliet livelli ta' granularità għall-iċċekkjar tagħhom: livelli ta 'ringiela, transazzjoni u espressjoni.
Postgres: bloat, pg_repack u restrizzjonijiet differiti
Sors: begriffs

CHECK u NOT NULL huma dejjem iċċekkjati fil-livell tar-ringiela; għal restrizzjonijiet oħra, kif jidher mit-tabella, hemm għażliet differenti. Tista' taqra aktar hawn.

Biex niġbru fil-qosor, restrizzjonijiet differiti f'numru ta 'sitwazzjonijiet jipprovdu kodiċi aktar leġibbli u inqas kmandi. Madankollu, trid tħallas għal dan billi tikkomplika l-proċess ta 'debugging, peress li l-mument li jseħħ l-iżball u l-mument li ssir taf dwaru huma separati fil-ħin. Problema oħra possibbli hija li l-iskeder jista 'mhux dejjem ikun kapaċi jibni pjan ottimali jekk it-talba tinvolvi restrizzjoni differita.

Titjib ta' pg_repack

Aħna koprejna x'inhuma r-restrizzjonijiet differiti, imma kif jirrelataw mal-problema tagħna? Ejja niftakru l-iżball li rċevejna qabel:

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

Dan iseħħ meta d-dejta tiġi kkupjata minn tabella ta’ log għal tabella ġdida. Din tidher stramba għax... id-dejta fit-tabella tar-reġistru hija impenjata flimkien mad-dejta fit-tabella tas-sors. Jekk jissodisfaw ir-restrizzjonijiet tat-tabella oriġinali, kif jistgħu jiksru l-istess restrizzjonijiet f'dik il-ġdida?

Kif jirriżulta, l-għerq tal-problema tinsab fil-pass preċedenti ta 'pg_repack, li joħloq biss indiċi, iżda mhux restrizzjonijiet: it-tabella l-antika kellha restrizzjoni unika, u l-ġdida ħolqot indiċi uniku minflok.

Postgres: bloat, pg_repack u restrizzjonijiet differiti

Huwa importanti li wieħed jinnota hawnhekk li jekk ir-restrizzjoni hija normali u mhux differita, allura l-indiċi uniku maħluq minflok huwa ekwivalenti għal dan ir-restrizzjoni, għaliex Limitazzjonijiet uniċi f'Postgres huma implimentati billi jinħoloq indiċi uniku. Iżda fil-każ ta 'restrizzjoni differita, l-imġieba mhix l-istess, minħabba li l-indiċi ma jistax jiġi differit u huwa dejjem iċċekkjat fil-ħin li jiġi esegwit il-kmand sql.

Għalhekk, l-essenza tal-problema tinsab fid-"dewmien" tal-kontroll: fit-tabella oriġinali sseħħ fil-ħin tal-kommit, u fit-tabella l-ġdida fil-ħin li jiġi esegwit il-kmand sql. Dan ifisser li rridu niżguraw li l-kontrolli jsiru bl-istess mod fiż-żewġ każijiet: jew dejjem ittardjati, jew dejjem immedjatament.

Allura x’ideat kellna?

Oħloq indiċi simili għal deferred

L-ewwel idea hija li twettaq iż-żewġ kontrolli fil-mod immedjat. Dan jista 'jiġġenera bosta restrizzjonijiet pożittivi foloz, iżda jekk ikun hemm ftit minnhom, dan m'għandux jaffettwa x-xogħol tal-utenti, peress li kunflitti bħal dawn huma sitwazzjoni normali għalihom. Jiġru, pereżempju, meta żewġ utenti jibdew jeditjaw l-istess widget fl-istess ħin, u l-klijent tat-tieni utent ma jkollux ħin biex jirċievi informazzjoni li l-widget huwa diġà mblukkat għall-editjar mill-ewwel utent. F'sitwazzjoni bħal din, is-server jirrifjuta lit-tieni utent, u l-klijent tiegħu jreġġa' lura l-bidliet u jimblokka l-widget. Ftit aktar tard, meta l-ewwel utent itemm l-editjar, it-tieni jirċievi informazzjoni li l-widget m'għadux imblukkat u se jkun jista 'jirrepeti l-azzjoni tiegħu.

Postgres: bloat, pg_repack u restrizzjonijiet differiti

Biex niżguraw li l-kontrolli jkunu dejjem fil-modalità mhux differita, ħloqna indiċi ġdid simili għar-restrizzjoni differita oriġinali:

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

Fl-ambjent tat-test, irċevejna biss ftit żbalji mistennija. Suċċess! Erġajna għamilna pg_repack fuq il-produzzjoni u ltqajna 5 żbalji fuq l-ewwel cluster f'siegħa xogħol. Dan huwa riżultat aċċettabbli. Madankollu, diġà fuq it-tieni cluster in-numru ta 'żbalji żdied b'mod sinifikanti u kellna nieqfu pg_repack.

Għaliex ġara? Il-probabbiltà li jseħħ żball tiddependi minn kemm utenti qed jaħdmu bl-istess widgets fl-istess ħin. Apparentement, f'dak il-mument kien hemm ħafna inqas bidliet kompetittivi bid-dejta maħżuna fuq l-ewwel cluster milli fuq l-oħrajn, i.e. konna biss "xxurtjati".

L-idea ma ħadmitx. F'dak il-punt, rajna żewġ soluzzjonijiet oħra: ikteb mill-ġdid il-kodiċi tal-applikazzjoni tagħna biex teħles minn restrizzjonijiet differiti, jew "jgħallmu" pg_repack biex taħdem magħhom. Għażilna t-tieni waħda.

Ibdel l-indiċi fit-tabella l-ġdida b'restrizzjonijiet differiti mit-tabella oriġinali

L-iskop tar-reviżjoni kien ovvju - jekk it-tabella oriġinali għandha restrizzjoni differita, allura għal dik il-ġdida għandek bżonn toħloq tali restrizzjoni, u mhux indiċi.

Biex nittestjaw il-bidliet tagħna, ktibna test sempliċi:

  • tabella b'restrizzjoni differita u rekord wieħed;
  • daħħal data f'linja li tikkonflitti ma' rekord eżistenti;
  • agħmel aġġornament - id-dejta m'għadhiex tikkonflitti;
  • jikkommettu l-bidliet.

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;

Il-verżjoni oriġinali ta 'pg_repack dejjem ġġarraf fl-ewwel daħħal, il-verżjoni modifikata ħadmet mingħajr żbalji. Kbir.

Immorru għall-produzzjoni u nerġgħu nġibu żball fl-istess fażi tal-ikkuppjar tad-dejta mit-tabella tar-reġistru għal waħda ġdida:

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

Sitwazzjoni klassika: kollox jaħdem f'ambjenti tat-test, iżda mhux fil-produzzjoni?!

APPLY_COUNT u l-junction ta' żewġ lottijiet

Bdejna nanalizzaw il-kodiċi litteralment linja b'linja u skoprejna punt importanti: id-dejta tiġi trasferita mit-tabella tar-reġistru għal waħda ġdida f'lottijiet, il-kostanti APPLY_COUNT indikat id-daqs tal-lott:

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

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

Il-problema hija li d-dejta mit-tranżazzjoni oriġinali, li fiha diversi operazzjonijiet jistgħu potenzjalment jiksru r-restrizzjoni, meta tiġi trasferita, tista 'tispiċċa fil-junction ta' żewġ lottijiet - nofs il-kmandi se jiġu impenjati fl-ewwel lott, u n-nofs l-ieħor fit-tieni. U hawn, skond ix-xorti tiegħek: jekk it-timijiet ma jiksru xejn fl-ewwel lott, allura kollox huwa tajjeb, imma jekk jagħmlu dan, iseħħ żball.

APPLY_COUNT huwa ugwali għal 1000 rekord, li jispjega għaliex it-testijiet tagħna kienu ta' suċċess - ma koprewx il-każ ta' "junction tal-lott". Aħna użajna żewġ kmandi - daħħal u aġġorna, għalhekk eżattament 500 tranżazzjoni ta 'żewġ kmandi dejjem tqiegħdu f'lott u ma esperjenzajna l-ebda problemi. Wara li żiedet it-tieni aġġornament, l-editjar tagħna waqaf jaħdem:

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;

Għalhekk, il-kompitu li jmiss huwa li tiżgura li d-dejta mit-tabella oriġinali, li nbidlet fi tranżazzjoni waħda, tispiċċa fit-tabella l-ġdida wkoll fi tranżazzjoni waħda.

Rifjut minn batching

U għal darb'oħra kellna żewġ soluzzjonijiet. L-ewwel: ejja nabbandunaw kompletament il-qsim f'lottijiet u tittrasferixxi d-data fi tranżazzjoni waħda. Il-vantaġġ ta 'din is-soluzzjoni kien is-sempliċità tagħha - il-bidliet meħtieġa fil-kodiċi kienu minimi (mill-mod, f'verżjonijiet anzjani pg_reorg ħadem eżattament hekk). Iżda hemm problema - qed noħolqu tranżazzjoni fit-tul, u dan, kif intqal qabel, huwa theddida għall-emerġenza ta 'bloat ġdid.

It-tieni soluzzjoni hija aktar kumplessa, iżda probabbilment aktar korretta: toħloq kolonna fit-tabella tal-ġurnal bl-identifikatur tat-tranżazzjoni li żiedet id-dejta mat-tabella. Imbagħad, meta nikkopjaw id-dejta, nistgħu niġbruha b'dan l-attribut u niżguraw li l-bidliet relatati jiġu trasferiti flimkien. Il-lott se jkun iffurmat minn diversi tranżazzjonijiet (jew waħda kbira) u d-daqs tiegħu se jvarja skond kemm id-dejta nbidlet f'dawn it-tranżazzjonijiet. Huwa importanti li wieħed jinnota li peress li d-dejta minn tranżazzjonijiet differenti tidħol fit-tabella tar-reġistru f'ordni każwali, mhux se jkun aktar possibbli li taqraha b'mod sekwenzjali, kif kien qabel. seqscan għal kull talba b'filtrazzjoni minn tx_id huwa għali wisq, huwa meħtieġ indiċi, iżda wkoll inaqqas il-metodu minħabba l-overhead tal-aġġornament tiegħu. B'mod ġenerali, bħal dejjem, għandek bżonn tissagrifika xi ħaġa.

Għalhekk, iddeċidejna li nibdew bl-ewwel għażla, peress li hija aktar sempliċi. L-ewwel, kien meħtieġ li wieħed jifhem jekk tranżazzjoni twila tkunx problema reali. Peress li t-trasferiment ewlieni tad-dejta mit-tabella l-antika għal dik il-ġdida jseħħ ukoll fi tranżazzjoni waħda twila, il-mistoqsija ttrasformat f'"kemm se nżidu din it-tranżazzjoni?" It-tul tal-ewwel tranżazzjoni jiddependi prinċipalment fuq id-daqs tat-tabella. It-tul ta’ żmien ġdid jiddependi fuq kemm jakkumulaw bidliet fit-tabella waqt it-trasferiment tad-dejta, i.e. fuq l-intensità tat-tagħbija. Il-ġirja pg_repack seħħet matul żmien ta 'tagħbija minima ta' servizz, u l-volum tal-bidliet kien żgħir b'mod sproporzjonat meta mqabbel mad-daqs oriġinali tat-tabella. Iddeċidejna li nistgħu nittraskuraw il-ħin ta 'tranżazzjoni ġdida (għal paragun, bħala medja hija siegħa 1 u minuti 2-3).

L-esperimenti kienu pożittivi. Tnedija fuq il-produzzjoni wkoll. Għaċ-ċarezza, hawn stampa bid-daqs ta 'waħda mid-databases wara t-tħaddim:

Postgres: bloat, pg_repack u restrizzjonijiet differiti

Peress li konna kompletament sodisfatti b'din is-soluzzjoni, ma ppruvajniex nimplimentaw it-tieni waħda, iżda qed nikkunsidraw il-possibbiltà li niddiskutuha mal-iżviluppaturi tal-estensjoni. Ir-reviżjoni attwali tagħna, sfortunatament, għadha mhix lesta għall-pubblikazzjoni, peress li solvejna l-problema biss b'restrizzjonijiet differiti uniċi, u għal garża sħiħa huwa meħtieġ li nipprovdu appoġġ għal tipi oħra. Nittamaw li nkunu nistgħu nagħmlu dan fil-futur.

Forsi għandek mistoqsija, għaliex aħna saħansitra nvolvu ruħna f'din l-istorja bil-modifika ta 'pg_repack, u ma użajnax, pereżempju, l-analogi tagħha? F'xi punt ħsibna wkoll dwar dan, iżda l-esperjenza pożittiva li nużawha aktar kmieni, fuq tabelli mingħajr restrizzjonijiet differiti, immotivatna biex nippruvaw nifhmu l-essenza tal-problema u nirranġawha. Barra minn hekk, l-użu ta 'soluzzjonijiet oħra jeħtieġ ukoll iż-żmien biex isiru testijiet, għalhekk iddeċidejna li l-ewwel nippruvaw nirranġaw il-problema fiha, u jekk indunaw li ma nistgħux nagħmlu dan fi żmien raġonevoli, allura nibdew inħarsu lejn l-analogi. .

Sejbiet

Dak li nistgħu nirrakkomandaw ibbażat fuq l-esperjenza tagħna stess:

  1. Immonitorja l-bloat tiegħek. Ibbażat fuq data ta 'monitoraġġ, tista' tifhem kemm l-autovacuum huwa kkonfigurat tajjeb.
  2. Aġġusta AUTOVACUUM biex iżżomm nefħa f'livell aċċettabbli.
  3. Jekk il-bloat għadu qed jikber u ma tistax tegħlebha billi tuża għodod barra mill-kaxxa, tibżax tuża estensjonijiet esterni. Il-ħaġa prinċipali hija li tittestja kollox sew.
  4. Tibżax timmodifika s-soluzzjonijiet esterni skont il-bżonnijiet tiegħek - xi kultant dan jista' jkun aktar effettiv u saħansitra aktar faċli milli tibdel il-kodiċi tiegħek stess.

Sors: www.habr.com

Żid kumment