PostgreSQL Antipatterns: promijenite podatke zaobilazeći okidač

Prije ili kasnije, mnogi se susreću s potrebom masovnog popravljanja nečega u evidenciji tablice. Već sam reci mi kako to učiniti bolje, a kako - bolje je ne raditi. Danas ću govoriti o drugom aspektu masovnog ažuriranja - o okidačima.

Na primjer, na stolu u kojem trebate nešto popraviti, visi zli okidač ON UPDATE, prenoseći sve promjene na neke agregate. I morate ažurirati sve (inicijalizirati novo polje, na primjer) tako pažljivo da ti agregati ne budu pogođeni.

Samo isključimo okidače!

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

Zapravo, to je sve - sve visi.

Jer ALTER TABLE nameće Ekskluzivni pristup- brava pod kojom nitko ne trči paralelno, čak ni jednostavan SELECT, neće moći pročitati ništa iz tablice. Odnosno, dok ova transakcija ne završi, čekat će svi koji žele čak i "samo čitati". I mi to pamtimo UPDATE imamo dugo ...

Brzo ugasimo, pa brzo upalimo!

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

UPDATE ...;

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

Ovdje je situacija već bolja, vrijeme čekanja je puno manje. Ali samo dva problema kvare svu ljepotu:

  • ALTER TABLE sam čeka sve druge operacije na stolu, uključujući i duge SELECT
  • Dok je okidač isključen, "proleti" svaka promjena u tablici, čak ni naše. I neće ući u agregate, iako bi trebalo. nevolje!

Upravljanje varijablama sesije

Dakle, u prethodnoj verziji smo naletjeli na temeljnu točku - moramo nekako naučiti okidač da razlikuje "naše" promjene u tablici od "ne naših". “Naši” se preskaču kakvi jesu, ali na “ne naši” se aktiviraju. Za ovo možete koristiti varijable sesije.

uloga_replikacije_sesije

čitati priručnik:

Na mehanizam okidača također utječe konfiguracijska varijabla uloga_replikacije_sesije. Omogućeno bez dodatnih uputa (zadano), okidači će se aktivirati kada je uloga replikacije "podrijetlo" (zadano) ili "lokalno". Okidači omogućeni određivanjem ENABLE REPLICA, radit će samo ako način trenutne sesije - "replika", a okidači omogućeni određivanjem ENABLE ALWAYS, radit će bez obzira na trenutni način replikacije.

Posebno ću naglasiti da se postavka ne odnosi na sve-sve odjednom, kao ALTER TABLE, ali samo na našu posebnu posebnu vezu. Ukupno, tako da nijedan okidač aplikacije ne radi:

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

Stanje unutar okidača

Ali gornja opcija radi za sve okidače odjednom (ili morate unaprijed "izmijeniti" okidače koje ne želite onemogućiti). I ako nam treba "isključiti" jedan određeni okidač?

Ovo će nam pomoći "korisnička" varijabla sesije:

Nazivi parametara proširenja pišu se na sljedeći način: naziv proširenja nakon kojeg slijedi točka, a zatim sam naziv parametra, slično punim nazivima objekata u SQL-u. Na primjer: plpgsql.variable_conflict.
Budući da se opcije izvan sustava mogu postaviti u procesima koji ne učitavaju odgovarajući modul proširenja, PostgreSQL prihvaća vrijednosti za sva imena s dvije komponente.

Prvo finaliziramo okidač, otprilike ovako:

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;
...

Usput, to se može učiniti "za profit", bez blokiranja, putem CREATE OR REPLACE za funkciju okidača. I onda u posebnoj vezi zakucamo "našu" varijablu:


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

Znate li druge načine? Podijelite u komentarima.

Izvor: www.habr.com

Dodajte komentar