PostgreSQL Antipatterns: ndryshoni të dhënat duke anashkaluar një shkas

Herët a vonë, shumë njerëz përballen me nevojën për të korrigjuar masivisht diçka në të dhënat e tabelave. Unë tashmë kam më tha se si ta bëja më mirë, dhe si - është më mirë të mos e bësh. Sot do të flas për aspektin e dytë të përditësimit masiv - rreth nxitësve.

Për shembull, në një tryezë në të cilën duhet të korrigjoni diçka, ekziston një shkas i keq ON UPDATE, duke transferuar të gjitha ndryshimet në disa agregate. Dhe ju duhet të përditësoni gjithçka (të inicializoni një fushë të re, për shembull) me aq kujdes që këto njësi të mos preken.

Le të fikim vetëm shkasat!

BEGIN;
  ALTER TABLE ... DISABLE TRIGGER ...;
  UPDATE ...; -- тут долго-долго
  ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;

Në fakt, kjo është e gjitha - gjithçka tashmë është e varur.

sepse ALTER TABLE imponon AccessExclusive-bravë nën të cilën askush nuk ecën paralelisht, qoftë edhe i thjeshtë SELECT, nuk do të jetë në gjendje të lexojë asgjë nga tabela. Kjo do të thotë, derisa të përfundojë ky transaksion, të gjithë ata që duan të "thjesht lexojnë" do të presin. Dhe ne e kujtojmë atë UPDATE kemi një kohë të gjatë...

Le ta fikim shpejt, pastaj ta ndezim shpejt!

BEGIN;
  ALTER TABLE ... DISABLE TRIGGER ...;
COMMIT;

UPDATE ...;

BEGIN;
  ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;

Këtu situata është tashmë më e mirë, koha e pritjes është dukshëm më e vogël. Por vetëm dy probleme prishin gjithë bukurinë:

  • ALTER TABLE vetë pret për të gjitha operacionet e tjera në tryezë, përfshirë ato të gjata SELECT
  • Ndërsa këmbëza është e fikur, çdo ndryshim do të "fluturojë" në tavolinë, as tonën. Dhe nuk do të hyjë në njësi, megjithëse duhet. Telashe!

Menaxhimi i variablave të sesionit

Pra, në versionin e mëparshëm hasëm në një pikë themelore - duhet të mësojmë disi shkasin të dallojë ndryshimet "tona" në tabelë nga "jo tonat". "E jona" anashkalohet siç është, dhe "jo e jona" aktivizohet. Për këtë ju mund të përdorni variablat e sesionit.

sesioni_replikimi_roli

Ne lexojmë manual:

Mekanizmi i ndezjes ndikohet gjithashtu nga ndryshorja e konfigurimit sesioni_replikimi_roli. Kur aktivizohet pa udhëzime të mëtejshme (e parazgjedhur), aktivizuesit do të aktivizohen kur roli i përsëritjes është "origjina" (i parazgjedhur) ose "lokal". Aktivizuesit aktivizohen nga udhëzimet ENABLE REPLICA, do të funksionojë vetëm nëse modaliteti aktual i seancës - "kopje", dhe aktivizuesit aktivizohen duke specifikuar ENABLE ALWAYS, do të aktivizohet pavarësisht nga mënyra aktuale e riprodhimit.

Dua të theksoj veçanërisht se cilësimi nuk vlen për të gjithë menjëherë, si ALTER TABLE, por vetëm për lidhjen tonë të veçantë të veçantë. Në total, në mënyrë që asnjë shkaktar i aplikacionit të mos aktivizohet:

SET session_replication_role = replica; -- выключили триггеры
UPDATE ...;
SET session_replication_role = DEFAULT; -- вернули в исходное состояние

Gjendja brenda një këmbëze

Por opsioni i mësipërm funksionon për të gjithë nxitësit menjëherë (ose ju duhet të "ndryshoni" paraprakisht shkaktarët që nuk dëshironi të çaktivizoni). Dhe nëse kemi nevojë "fik" një shkas specifik?

Kjo do të na ndihmojë ndryshorja e sesionit "përdorues".:

Emrat e parametrave të zgjerimit shkruhen si më poshtë: emri i zgjerimit, pika, dhe më pas emri i parametrit vetë, i ngjashëm me emrat e objekteve plotësisht të kualifikuar në SQL. Për shembull: plpgsql.variable_conflict.
Meqenëse opsionet jo të sistemit mund të vendosen në procese që nuk ngarkojnë modulin përkatës të zgjerimit, PostgreSQL pranon vlerat për çdo emër me dy përbërës.

Së pari ne modifikojmë këmbëzën, diçka si kjo:

BEGIN
    -- процессу конвертации можно делать все
    IF current_setting('mycfg.my_table_convert_process') = 'TRUE' THEN
        IF TG_OP IN ('INSERT', 'UPDATE') THEN
            RETURN NEW;
        ELSE
            RETURN OLD;
        END IF;
    END IF;
...

Nga rruga, kjo mund të bëhet "live", pa bllokuar, përmes CREATE OR REPLACE për funksionin e këmbëzës. Dhe më pas në lidhjen speciale vendosëm ndryshoren "tonë":


SET mycfg.my_table_convert_process = 'TRUE';
UPDATE ...;
SET mycfg.my_table_convert_process = ''; -- вернули в исходное состояние

A dini mënyra të tjera? Ndani në komente.

Burimi: www.habr.com

Shto një koment