Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong

Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong

Ang epekto sa bloat sa mga lamesa ug mga indeks kay kaylap nga nailhan ug anaa dili lamang sa Postgres. Adunay mga paagi sa pag-atubang niini sa gawas sa kahon, sama sa VACUUM FULL o CLUSTER, apan gi-lock nila ang mga lamesa sa panahon sa operasyon ug busa dili kanunay magamit.

Ang artikulo maglangkob sa gamay nga teorya bahin sa kung giunsa mahitabo ang bloat, kung giunsa nimo kini pakigbatok, bahin sa mga gilangan nga pagpugong ug ang mga problema nga gidala nila sa paggamit sa extension sa pg_repack.

Kini nga artikulo gisulat base sa akong sinultihan sa PgConf.Russia 2020.

Nganong mahitabo ang bloat?

Ang mga postgres gibase sa usa ka multi-bersyon nga modelo (MVCC). Ang esensya niini mao nga ang matag laray sa lamesa mahimong adunay daghang mga bersyon, samtang ang mga transaksyon makita nga dili labaw sa usa niini nga mga bersyon, apan dili kinahanglan nga parehas. Gitugotan niini ang daghang mga transaksyon nga molihok nga dungan ug halos wala’y epekto sa usag usa.

Dayag, kining tanan nga mga bersyon kinahanglang tipigan. Ang mga postgres nagtrabaho sa panid sa panumduman sa panid ug usa ka panid ang labing gamay nga kantidad sa datos nga mabasa gikan sa disk o gisulat. Atong tan-awon ang usa ka gamay nga pananglitan aron masabtan kung giunsa kini mahitabo.

Ingnon ta nga kita adunay usa ka lamesa diin kita nagdugang daghang mga rekord. Ang bag-ong datos nagpakita sa unang panid sa file diin ang lamesa gitipigan. Kini ang mga buhi nga bersyon sa mga linya nga magamit sa ubang mga transaksyon pagkahuman sa usa ka commit (alang sa kayano, atong hunahunaon nga ang lebel sa pagkalain kay Read Committed).

Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong

Dayon among gi-update ang usa sa mga entri, sa ingon nagtimaan sa daan nga bersyon nga wala nay kalabutan.

Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong

Sa lakang sa lakang, pag-update ug pagtangtang sa mga bersyon sa linya, natapos namon ang usa ka panid diin hapit katunga sa datos ang "basura". Kini nga datos dili makita sa bisan unsang transaksyon.

Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong

Ang mga postgres adunay mekanismo VACUUM, nga naglimpyo sa karaan nga mga bersyon ug naghatag ug lugar alang sa bag-ong datos. Apan kung kini dili igo nga agresibo nga pag-configure o busy sa pagtrabaho sa ubang mga lamesa, nan ang "data sa basura" nagpabilin, ug kinahanglan namon nga mogamit dugang nga mga panid alang sa bag-ong datos.

Mao nga sa among panig-ingnan, sa usa ka punto sa oras ang lamesa maglangkob sa upat ka mga panid, apan katunga ra niini adunay sulud nga live data. Ingon usa ka sangputanan, kung mag-access sa lamesa, magbasa kami labi pa nga datos kaysa kinahanglan.

Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong

Bisan kung tangtangon na karon sa VACUUM ang tanan nga wala’y kalabotan nga mga bersyon sa linya, ang kahimtang dili kaayo mouswag. Kita adunay libre nga luna sa mga panid o bisan sa tibuok nga mga panid alang sa bag-ong mga laray, apan kita sa gihapon magbasa sa dugang nga datos kay sa gikinahanglan.
Pinaagi sa dalan, kung ang usa ka bug-os nga blangko nga panid (ang ikaduha sa among pananglitan) naa sa katapusan sa file, nan ang VACUUM makahimo sa pagputol niini. Apan karon anaa na siya sa tunga-tunga, mao nga wala nay mahimo kaniya.

Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong

Sa diha nga ang gidaghanon sa ingon nga walay sulod o hilabihan ka gamay nga mga panid mahimong dako, nga gitawag bloat, kini magsugod sa pag-apektar sa performance.

Ang tanan nga gihulagway sa ibabaw mao ang mga mekaniko sa panghitabo sa bloat sa mga lamesa. Sa mga indeks, kini mahitabo sa parehas nga paagi.

Naa koy bloat?

Adunay daghang mga paagi aron mahibal-an kung ikaw adunay bloat. Ang ideya sa una mao ang paggamit sa internal nga mga istatistika sa Postgres, nga adunay gibanabana nga kasayuran bahin sa gidaghanon sa mga laray sa mga lamesa, ang gidaghanon sa mga "live" nga mga laray, ug uban pa. Makita nimo ang daghang mga kalainan sa andam nga mga script sa Internet. Gikuha namo isip basehan script gikan sa Mga Eksperto sa PostgreSQL, nga makatimbang-timbang sa mga bloat table kauban ang toast ug bloat btree index. Sa among kasinatian, ang sayup niini 10-20%.

Ang laing paagi mao ang paggamit sa extension pgstattuple, nga nagtugot kanimo sa pagtan-aw sa sulod sa mga panid ug pagkuha sa usa ka gibanabana ug usa ka eksaktong bloat nga kantidad. Apan sa ikaduha nga kaso, kinahanglan nimo nga i-scan ang tibuuk nga lamesa.

Giisip namon ang gamay nga kantidad sa bloat, hangtod sa 20%, madawat. Mahimo kini isipon nga usa ka analogue sa fillfactor alang sa mga lamesa и mga indeks. Sa 50% pataas, mahimong magsugod ang mga problema sa pasundayag.

Mga paagi sa pagbatok sa bloat

Ang mga postgres adunay daghang mga paagi sa pag-atubang sa bloat gikan sa kahon, apan dili kini kanunay nga angay alang sa tanan.

I-configure ang AUTOVACUUM aron dili mahitabo ang bloat. O mas tukma, aron mapadayon kini sa lebel nga madawat nimo. Daw sama kini sa tambag sa "kapitan", apan sa pagkatinuod kini dili kanunay sayon ​​nga makab-ot. Pananglitan, ikaw adunay aktibo nga pag-uswag nga adunay regular nga pagbag-o sa eskema sa datos, o usa ka matang sa pagbalhin sa datos nga nahitabo. Ingon nga resulta, ang imong load profile mahimong mausab kanunay ug kasagaran magkalahi gikan sa lamesa ngadto sa lamesa. Kini nagpasabut nga kinahanglan nimo nga kanunay nga magtrabaho sa unahan ug i-adjust ang AUTOVACUUM sa pagbag-o sa profile sa matag lamesa. Apan klaro nga dili kini sayon ​​nga buhaton.

Laing komon nga rason nganong dili makasunod sa mga lamesa ang AUTOVACUUM tungod kay adunay mga dugay na nga transaksyon nga nagpugong niini sa paglimpyo sa datos nga anaa sa maong mga transaksyon. Ang rekomendasyon dinhi klaro usab - kuhaa ang mga "nagbitay" nga mga transaksyon ug maminusan ang oras sa aktibo nga mga transaksyon. Apan kung ang pagkarga sa imong aplikasyon usa ka hybrid sa OLAP ug OLTP, nan mahimo ka nga dungan nga adunay daghang kanunay nga pag-update ug mubu nga mga pangutana, ingon man mga dugay nga operasyon - pananglitan, paghimo usa ka taho. Sa ingon nga sitwasyon, angay nga hunahunaon ang pagsabwag sa load sa lainlaing mga base, nga magtugot alang sa dugang nga pag-ayo sa matag usa kanila.

Laing pananglitan - bisan kung ang profile homogenous, apan ang database ubos sa taas kaayo nga load, nan bisan ang labing agresibo nga AUTOVACUUM mahimong dili makasagubang, ug mahitabo ang bloat. Ang scaling (vertical o horizontal) mao lamang ang solusyon.

Unsa ang buhaton sa usa ka sitwasyon nga imong gi-set up ang AUTOVACUUM, apan ang bloat nagpadayon sa pagtubo.

team NAPUNO ANG VACUUM nagtukod pag-usab sa mga sulod sa mga lamesa ug mga indeks ug nagbilin lamang ug may kalabutan nga datos diha niini. Aron mawagtang ang bloat, kini nagtrabaho sa hingpit, apan sa panahon sa pagpatuman niini usa ka eksklusibong lock sa lamesa ang nakuha (AccessExclusiveLock), nga dili magtugot sa pagpatuman sa mga pangutana niini nga lamesa, bisan sa pagpili. Kung mahimo nimo nga ihunong ang imong serbisyo o bahin niini sa pipila ka panahon (gikan sa napulo ka minuto hangtod sa daghang oras depende sa gidak-on sa database ug sa imong hardware), nan kini nga kapilian mao ang labing kaayo. Ikasubo, wala kami panahon sa pagdagan sa VACUUM FULL sa panahon sa gikatakda nga pagmentinar, mao nga kini nga pamaagi dili angay alang kanamo.

team CLUSTER Gitukod pag-usab ang mga sulud sa mga lamesa sa parehas nga paagi sama sa VACUUM FULL, apan gitugotan ka sa pagtino sa usa ka indeks kung diin ang data pisikal nga gimando sa disk (apan sa umaabot ang order dili garantiya alang sa bag-ong mga laray). Sa pipila ka mga sitwasyon, kini usa ka maayo nga pag-optimize alang sa daghang mga pangutana - uban ang pagbasa sa daghang mga rekord pinaagi sa indeks. Ang disbentaha sa mando parehas sa VACUUM FULL - kini nag-lock sa lamesa sa panahon sa operasyon.

team REINDEX susama sa miaging duha, apan nagtukod pag-usab sa usa ka piho nga indeks o tanan nga mga indeks sa lamesa. Ang mga kandado gamay nga huyang: ShareLock sa lamesa (gipugngan ang mga pagbag-o, apan gitugotan ang pagpili) ug ang AccessExclusiveLock sa indeks nga gitukod pag-usab (gibabagan ang mga pangutana gamit kini nga indeks). Bisan pa, sa ika-12 nga bersyon sa Postgres usa ka parameter ang nagpakita SAMTANG, nga nagtugot kanimo sa pagtukod pag-usab sa indeks nga walay pagbabag sa dungan nga pagdugang, pagbag-o, o pagtangtang sa mga rekord.

Sa naunang mga bersyon sa Postgres, mahimo nimong makab-ot ang resulta nga susama sa REINDEX CONCURRENTLY gamit PAGHIMO INDEX DUGANG. Gitugotan ka niini nga maghimo usa ka indeks nga wala’y estrikto nga pag-lock (ShareUpdateExclusiveLock, nga dili makabalda sa managsama nga mga pangutana), unya pulihan ang daan nga indeks sa usa ka bag-o ug tangtangon ang daan nga indeks. Kini nagtugot kanimo sa pagwagtang sa index bloat nga dili makabalda sa imong aplikasyon. Mahinungdanon nga hunahunaon nga kung ang pagtukod pag-usab sa mga indeks adunay dugang nga pagkarga sa subsystem sa disk.

Busa, kung alang sa mga indeks adunay mga paagi sa pagwagtang sa bloat "sa langaw," nan wala'y alang sa mga lamesa. Dinhi diin nagdula ang lainlaing mga eksternal nga extension: pg_repack (kanhi pg_reorg), pgcompact, pgcompacttable ug uban pa. Niini nga artikulo, dili ko sila itandi ug maghisgot lamang bahin sa pg_repack, nga, human sa pipila ka kausaban, atong gamiton ang atong kaugalingon.

Giunsa pagtrabaho ang pg_repack

Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong
Ingnon ta nga kita adunay usa ka bug-os nga ordinaryo nga lamesa - nga adunay mga indeks, mga pagdili ug, sa kasubo, adunay bloat. Ang unang lakang sa pg_repack mao ang paghimo og talaan sa log aron tipigan ang datos mahitungod sa tanang kausaban samtang nagdagan. Ang gatilyo magsundog niini nga mga kausaban alang sa matag insert, update ug delete. Dayon ang usa ka lamesa gihimo, susama sa orihinal nga istruktura, apan walay mga indeks ug mga pagdili, aron dili mapahinay ang proseso sa pagsal-ot sa datos.

Sunod, gibalhin sa pg_repack ang datos gikan sa daan nga lamesa ngadto sa bag-ong lamesa, awtomatiko nga gisala ang tanan nga wala’y kalabotan nga mga laray, ug dayon nagmugna mga indeks alang sa bag-ong lamesa. Atol sa pagpatuman sa tanan niini nga mga operasyon, ang mga pagbag-o natipon sa talaan sa talaan.

Ang sunod nga lakang mao ang pagbalhin sa mga pagbag-o sa bag-ong lamesa. Ang paglalin gihimo sa daghang mga pag-uli, ug kung wala nay 20 ka mga entry ang nahabilin sa talaan sa log, ang pg_repack nakakuha usa ka lig-on nga kandado, gibalhin ang labing bag-ong datos, ug gipulihan ang daan nga lamesa sa bag-o sa mga lamesa sa sistema sa Postgres. Kini ra ug mubo ra kaayo nga panahon kung dili ka makatrabaho sa lamesa. Pagkahuman niini, ang daan nga lamesa ug ang lamesa nga adunay mga troso mapapas ug ang wanang gipagawas sa file system. Kompleto na ang proseso.

Ang tanan nindot tan-awon sa teorya, apan unsa ang mahitabo sa praktis? Among gisulayan ang pg_repack nga walay load ug ubos sa load, ug gisusi ang operasyon niini sa kaso sa ahat nga paghunong (sa laing pagkasulti, gamit ang Ctrl+C). Ang tanan nga mga pagsulay positibo.

Miadto kami sa tindahan sa pagkaon - ug unya ang tanan wala moadto sa among gilauman.

Unang pancake nga gibaligya

Sa una nga cluster nakadawat kami usa ka sayup bahin sa usa ka paglapas sa usa ka talagsaon nga pagpugong:

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

Kini nga limitasyon adunay auto-generated nga ngalan nga index_16508 - kini gimugna sa pg_repack. Pinasukad sa mga hiyas nga gilakip sa komposisyon niini, among gitino ang "among" pagpugong nga katumbas niini. Ang problema nahimo nga dili kini usa ka bug-os nga ordinaryo nga limitasyon, apan usa ka gilangan (gilangan nga pagpugong), i.e. ang pag-verify niini gihimo sa ulahi kaysa sa sql nga mando, nga nagdala sa wala damha nga mga sangputanan.

Gi-defer nga mga pagpugong: ngano nga kini gikinahanglan ug kung giunsa kini pagtrabaho

Usa ka gamay nga teorya bahin sa mga nalangan nga mga pagdili.
Atong tagdon ang usa ka yano nga pananglitan: kita adunay usa ka lamesa-reference nga libro sa mga sakyanan nga adunay duha ka mga hiyas - ang ngalan ug han-ay sa sakyanan sa direktoryo.
Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong

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



Ingnon ta nga kinahanglan namong ibaylo ang una ug ikaduhang mga sakyanan. Ang prangka nga solusyon mao ang pag-update sa una nga kantidad sa ikaduha, ug ang ikaduha sa una:

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

Apan kung gipadagan namon kini nga code, nagpaabut kami nga usa ka paglapas sa pagpugong tungod kay ang pagkasunud-sunod sa mga kantidad sa lamesa talagsaon:

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

Unsaon nako pagbuhat niini nga lahi? Usa nga kapilian: pagdugang usa ka dugang nga pagpuli sa kantidad sa usa ka order nga gigarantiyahan nga wala maglungtad sa lamesa, pananglitan "-1". Sa programming, gitawag kini nga "pagbaylo sa mga kantidad sa duha nga mga variable hangtod sa ikatulo." Ang bugtong disbentaha niini nga pamaagi mao ang dugang nga pag-update.

Ikaduhang kapilian: Idisenyo pag-usab ang lamesa aron magamit ang usa ka floating point data type alang sa order value imbes nga mga integer. Pagkahuman, kung gi-update ang kantidad gikan sa 1, pananglitan, hangtod sa 2.5, ang una nga pagsulod awtomatiko nga "mobarug" taliwala sa ikaduha ug ikatulo. Kini nga solusyon molihok, apan adunay duha nga mga limitasyon. Una, dili kini molihok alang kanimo kung ang kantidad gigamit sa usa ka lugar sa interface. Ikaduha, depende sa katukma sa tipo sa datos, adunay ka limitado nga gidaghanon sa posible nga mga pagsal-ot sa dili pa kalkulahon pag-usab ang mga kantidad sa tanan nga mga rekord.

Tulo nga kapilian: himoa nga ang pagpugong nga gilangan aron kini masusi lamang sa panahon sa pagpasalig:

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

Tungod kay ang lohika sa among una nga hangyo nagsiguro nga ang tanan nga mga kantidad talagsaon sa panahon sa pagpasalig, kini molampos.

Ang pananglitan nga gihisgutan sa ibabaw, siyempre, sintetiko kaayo, apan kini nagpadayag sa ideya. Sa among aplikasyon, gigamit namo ang mga deferred constraints aron ipatuman ang lohika nga responsable sa pagsulbad sa mga panagbangi kung ang mga tiggamit dungan nga magtrabaho sa gipaambit nga mga butang sa widget sa board. Ang paggamit sa ingon nga mga pagdili nagtugot kanamo sa paghimo sa code sa aplikasyon nga labi ka yano.

Sa kinatibuk-an, depende sa matang sa pagpugong, ang Postgres adunay tulo ka lebel sa granularity alang sa pagsusi niini: linya, transaksyon, ug lebel sa ekspresyon.
Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong
Source: mga beriff

Ang CHECK ug NOT NULL kanunay nga gisusi sa lebel sa linya; alang sa ubang mga pagdili, ingon sa makita sa lamesa, adunay lainlaing mga kapilian. Makabasa ka ug dugang dinhi.

Sa mubo nga pag-summarize, ang mga deferred constraints sa daghang mga sitwasyon naghatag og mas mabasa nga code ug mas gamay nga mga sugo. Bisan pa, kinahanglan nimo nga bayran kini pinaagi sa pagkomplikado sa proseso sa pag-debug, tungod kay sa higayon nga mahitabo ang sayup ug sa higayon nga nahibal-an nimo kini gibulag sa oras. Ang laing posible nga problema mao nga ang scheduler dili kanunay makahimo sa usa ka labing maayo nga plano kon ang hangyo naglakip sa usa ka deferred pagpugong.

Pag-uswag sa pg_repack

Nahisgotan na namo kung unsa ang mga deferred constraints, apan unsa may kalabotan niini sa among problema? Atong hinumdoman ang sayop nga atong nadawat sa sayo pa:

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

Kini mahitabo sa diha nga ang data gikopya gikan sa usa ka talaan sa talaan ngadto sa usa ka bag-ong lamesa. Kini tan-awon nga katingad-an tungod kay ... ang datos sa talaan sa talaan gihimo uban sa datos sa talaan sa tinubdan. Kung gitagbaw nila ang mga pagpugong sa orihinal nga lamesa, giunsa nila paglapas ang parehas nga mga pagpugong sa bag-o?

Ingon nga kini nahimo, ang gamut sa problema anaa sa miaging lakang sa pg_repack, nga nagmugna lamang sa mga indeks, apan dili mga pagpugong: ang daan nga lamesa adunay usa ka talagsaon nga pagpugong, ug ang bag-o naghimo sa usa ka talagsaon nga indeks sa baylo.

Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong

Mahinungdanon nga timan-an dinhi nga kung ang pagpugong kay normal ug dili gi-defer, nan ang talagsaon nga indeks nga gihimo sa baylo katumbas sa kini nga pagpugong, tungod kay Ang talagsaon nga mga pagpugong sa Postgres gipatuman pinaagi sa paghimo og usa ka talagsaon nga indeks. Apan sa kaso sa usa ka deferred nga pagpugong, ang kinaiya dili pareho, tungod kay ang indeks dili ma-defer ug kanunay nga gisusi sa panahon nga ang sql command gipatuman.

Busa, ang esensya sa problema anaa sa "paglangan" sa tseke: sa orihinal nga lamesa kini mahitabo sa panahon sa commit, ug sa bag-ong lamesa sa panahon nga ang sql command gipatuman. Nagpasabot kini nga kinahanglan natong sigurohon nga ang mga pagsusi gihimo nga pareho sa duha ka mga kaso: kanunay nga nalangan, o kanunay nga diha-diha dayon.

Busa unsa ang atong mga ideya?

Paghimo og index nga susama sa deferred

Ang unang ideya mao ang paghimo sa duha ka mga tseke sa diha-diha nga paagi. Mahimong makamugna kini og daghang sayup nga positibo nga mga pagdili, apan kung adunay pipila niini, dili kini makaapekto sa trabaho sa mga tiggamit, tungod kay ang ingon nga mga panagbangi usa ka normal nga kahimtang alang kanila. Kini mahitabo, pananglitan, sa dihang ang duha ka tiggamit magsugod sa pag-edit sa samang widget sa samang higayon, ug ang kliyente sa ikaduhang user walay panahon sa pagdawat sa impormasyon nga ang widget gibabagan na alang sa pag-edit sa unang user. Sa ingon nga sitwasyon, ang server nagdumili sa ikaduha nga tiggamit, ug ang kliyente niini mibalik sa mga pagbag-o ug gibabagan ang widget. Usa ka gamay nga ulahi, kung ang una nga tiggamit makompleto ang pag-edit, ang ikaduha makadawat kasayuran nga ang widget wala na gibabagan ug mahimo’g masubli ang ilang aksyon.

Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong

Aron masiguro nga ang mga tseke kanunay anaa sa non-deferred mode, naghimo kami og bag-ong index nga susama sa orihinal nga deferred constraint:

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

Sa palibot sa pagsulay, nakadawat kami pipila ra nga gipaabut nga mga sayup. Kalampusan! Nagdagan kami pag-usab sa pg_repack sa produksiyon ug nakakuha og 5 nga mga sayup sa una nga cluster sa usa ka oras nga pagtrabaho. Kini usa ka madawat nga resulta. Bisan pa, naa sa ikaduha nga cluster ang gidaghanon sa mga kasaypanan miuswag pag-ayo ug kinahanglan namong ihunong ang pg_repack.

Ngano nahitabo ni? Ang posibilidad sa usa ka sayup nga mahitabo nagdepende kung pila ang mga tiggamit nga nagtrabaho sa parehas nga mga widget sa parehas nga oras. Dayag, niadtong higayona adunay mas gamay nga kompetisyon nga mga kausaban sa mga datos nga gitipigan sa unang cluster kay sa uban, i.e. "swerte" lang kami.

Ang ideya wala molihok. Nianang puntoha, nakakita kami og laing duha ka mga solusyon: isulat pag-usab ang among code sa aplikasyon aron mawagtang ang mga deferred constraints, o "itudlo" ang pg_repack sa pagtrabaho uban kanila. Gipili namo ang ikaduha.

Ilisan ang mga indeks sa bag-ong lamesa nga adunay mga deferred constraints gikan sa orihinal nga lamesa

Ang katuyoan sa pagbag-o klaro - kung ang orihinal nga lamesa adunay usa ka gilangan nga pagpugong, nan alang sa bag-o kinahanglan nimo nga maghimo usa ka pagpugong, ug dili usa ka indeks.

Aron masulayan ang among mga pagbag-o, nagsulat kami usa ka yano nga pagsulay:

  • lamesa nga adunay gilangan nga pagpugong ug usa ka rekord;
  • isulod ang datos sa usa ka loop nga sukwahi sa usa ka kasamtangan nga rekord;
  • paghimo og update - ang data dili na magkasumpaki;
  • itugyan ang mga pagbag-o.

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;

Ang orihinal nga bersyon sa pg_repack kanunay nga nahagsa sa unang insert, ang giusab nga bersyon nagtrabaho nga walay mga sayup. Nindot.

Moadto kami sa produksiyon ug makakuha usab usa ka sayup sa parehas nga yugto sa pagkopya sa datos gikan sa talaan sa log ngadto sa usa ka bag-o:

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

Klasikong kahimtang: ang tanan nagtrabaho sa mga palibot sa pagsulay, apan dili sa produksiyon?!

APPLY_COUNT ug ang junction sa duha ka batch

Nagsugod kami sa pag-analisar sa code sa literal nga linya sa linya ug nakadiskobre sa usa ka importante nga punto: ang data gibalhin gikan sa log table ngadto sa usa ka bag-o sa mga batch, ang APPLY_COUNT nga kanunay nagpakita sa gidak-on sa batch:

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

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

Ang problema mao nga ang datos gikan sa orihinal nga transaksyon, diin ang daghang mga operasyon mahimo’g makalapas sa pagpugong, kung gibalhin, mahimong matapos sa junction sa duha ka batch - ang katunga sa mga mando himuon sa una nga batch, ug ang laing katunga. sa ikaduha. Ug dinhi, depende sa imong swerte: kung ang mga koponan wala makalapas sa bisan unsang butang sa una nga batch, nan maayo ang tanan, apan kung buhaton nila, adunay usa ka sayup nga mahitabo.

Ang APPLY_COUNT katumbas sa 1000 ka mga rekord, nga nagpatin-aw ngano nga malampuson ang among mga pagsulay - wala nila masakop ang kaso sa "batch junction". Gigamit namo ang duha ka mga sugo - pagsal-ot ug pag-update, mao nga eksakto nga 500 ka mga transaksyon sa duha ka mga sugo ang kanunay gibutang sa usa ka batch ug wala kami makasinati og bisan unsang mga problema. Human sa pagdugang sa ikaduhang update, ang among pag-edit mihunong sa pagtrabaho:

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;

Busa, ang sunod nga buluhaton mao ang pagsiguro nga ang datos gikan sa orihinal nga lamesa, nga giusab sa usa ka transaksyon, mahuman sa bag-ong lamesa usab sulod sa usa ka transaksyon.

Pagdumili sa batching

Ug pag-usab kami adunay duha ka solusyon. Una: hingpit natong biyaan ang pagbahinbahin ngadto sa mga batch ug ibalhin ang datos sa usa ka transaksyon. Ang bentaha sa kini nga solusyon mao ang kayano niini - ang gikinahanglan nga mga pagbag-o sa code gamay ra (sa ingon, sa mga daan nga bersyon pg_reorg nagtrabaho nga sama niana). Apan adunay usa ka problema - naghimo kami usa ka dugay na nga transaksyon, ug kini, sama sa giingon kaniadto, usa ka hulga sa pagtunga sa usa ka bag-ong bloat.

Ang ikaduha nga solusyon mas komplikado, apan tingali mas husto: paghimo og kolum sa log table nga adunay identifier sa transaksyon nga nagdugang sa datos sa lamesa. Dayon, kon kita mokopya sa data, mahimo natong igrupo kini pinaagi niini nga hiyas ug siguruha nga ang mga may kalabutan nga mga pagbag-o gibalhin sa tingub. Ang batch maporma gikan sa daghang mga transaksyon (o usa ka dako) ug ang gidak-on niini magkalainlain depende kung pila ang datos nga nabag-o sa kini nga mga transaksyon. Mahinungdanon nga timan-an nga tungod kay ang mga datos gikan sa lainlaing mga transaksyon mosulod sa talaan sa log sa usa ka random nga pagkasunud, dili na posible nga basahon kini nga sunud-sunod, sama sa kaniadto. seqscan alang sa matag hangyo nga adunay pagsala pinaagi sa tx_id mahal kaayo, usa ka indeks ang gikinahanglan, apan kini usab magpahinay sa pamaagi tungod sa overhead sa pag-update niini. Sa kinatibuk-an, sama sa kanunay, kinahanglan nimo nga isakripisyo ang usa ka butang.

Busa, nakahukom kami nga magsugod sa una nga kapilian, tungod kay kini mas simple. Una, gikinahanglan nga masabtan kung ang usa ka taas nga transaksyon mahimong tinuod nga problema. Tungod kay ang nag-unang pagbalhin sa datos gikan sa daan nga lamesa ngadto sa bag-o mahitabo usab sa usa ka taas nga transaksyon, ang pangutana nausab ngadto sa "unsa kadaghan ang atong madugangan kini nga transaksyon?" Ang gidugayon sa unang transaksyon nag-agad nag-una sa gidak-on sa lamesa. Ang gidugayon sa usa ka bag-o nagdepende kung pila ang mga pagbag-o nga natipon sa lamesa sa panahon sa pagbalhin sa datos, i.e. sa intensity sa load. Ang pg_repack run nahitabo sa panahon nga gamay ra ang service load, ug ang gidaghanon sa mga pagbag-o gamay ra kung itandi sa orihinal nga gidak-on sa lamesa. Nakahukom kami nga mahimo namong pasagdan ang oras sa usa ka bag-ong transaksyon (alang sa pagtandi, sa kasagaran kini 1 ka oras ug 2-3 ka minuto).

Ang mga eksperimento positibo. Ilunsad usab sa produksyon. Alang sa katin-awan, ania ang usa ka litrato nga adunay gidak-on sa usa sa mga database pagkahuman sa pagdagan:

Mga postgres: bloat, pg_repack ug gi-defer nga mga pagpugong

Tungod kay kami hingpit nga natagbaw sa kini nga solusyon, wala kami mosulay sa pagpatuman sa ikaduha, apan among gikonsiderar ang posibilidad nga hisgutan kini sa mga nag-develop sa extension. Ang among kasamtangan nga pagbag-o, sa walay palad, dili pa andam alang sa pagmantala, tungod kay nasulbad ra namo ang problema sa talagsaon nga mga pagdili, ug alang sa usa ka bug-os nga patch gikinahanglan ang paghatag suporta alang sa ubang mga matang. Naglaum kami nga mahimo kini sa umaabot.

Tingali adunay ka pangutana, ngano nga naapil pa kami sa kini nga istorya sa pagbag-o sa pg_repack, ug wala, pananglitan, gigamit ang mga analogue niini? Sa usa ka punto naghunahuna usab kami bahin niini, apan ang positibo nga kasinatian sa paggamit niini sa sayo pa, sa mga lamesa nga wala’y paglangan nga mga pagpugong, nagdasig kanamo nga sulayan nga masabtan ang esensya sa problema ug ayohon kini. Dugang pa, ang paggamit sa ubang mga solusyon nanginahanglan usab og oras sa pagpahigayon sa mga pagsulay, mao nga nakahukom kami nga sulayan una namon nga ayohon ang problema niini, ug kung nahibal-an namon nga dili namon kini mahimo sa usa ka makatarunganon nga oras, nan magsugod kami sa pagtan-aw sa mga analogue. .

kaplag

Unsa ang among marekomendar base sa among kaugalingong kasinatian:

  1. Pag-monitor sa imong bloat. Pinasukad sa datos sa pag-monitor, masabtan nimo kung unsa ka maayo ang pag-configure sa autovacuum.
  2. I-adjust ang AUTOVACUUM aron magpabilin ang bloat sa madawat nga lebel.
  3. Kung ang bloat motubo pa ug dili nimo kini mabuntog gamit ang out-of-the-box nga mga himan, ayaw kahadlok sa paggamit sa mga eksternal nga extension. Ang nag-unang butang mao ang pagsulay sa tanan nga maayo.
  4. Ayaw kahadlok sa pag-usab sa mga eksternal nga solusyon aron mohaum sa imong mga panginahanglan - usahay kini mahimong mas epektibo ug mas sayon ​​pa kay sa pagbag-o sa imong kaugalingong code.

Source: www.habr.com

Idugang sa usa ka comment