PostgreSQL Antipatterns: cambiate i dati sguassendu un trigger

Prima o dopu, assai sò affruntati cù a necessità di riparà in massa qualcosa in i registri di a tavula. Aghju digià dimmi cumu fà megliu, è cumu - hè megliu ùn fà micca. Oghje parleraghju di u sicondu aspettu di l'aghjurnamentu di massa - circa triggers.

Per esempiu, nantu à una tavula in quale avete bisognu di riparà qualcosa, un gattivu malignu pende ON UPDATE, trasferendu tutti i cambiamenti à certi aggregati. È avete bisognu di aghjurnà tuttu (inizializà un novu campu, per esempiu) cusì cun cura chì questi aggregati ùn sò micca affettati.

Disattivemu solu i triggers!

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

In verità, hè tuttu - tuttu hè appiccicatu.

Perchè ALTER TABLE impone Accessu Esclusivu- una serratura sottu à quale nimu corre in parallelu, ancu un simplice SELECT, ùn puderà micca leghje nunda da a tavula. Questu hè, finu à a fine di sta transazzione, tutti quelli chì volenu ancu "leghje solu" aspittàranu. È ricurdate chì UPDATE avemu una longa...

Spegnemu rapidamente, poi accendemu prestu !

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

UPDATE ...;

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

Quì a situazione hè digià megliu, u tempu d'attesa hè assai menu. Ma solu dui prublemi sguassate tutta a bellezza:

  • ALTER TABLE ellu stessu aspetta per tutte e altre operazioni nantu à a tavula, cumpresi i longu SELECT
  • Mentre u grillu hè spento, "fly by" ogni cambiamentu in tavula, mancu a nostra. È ùn entrerà micca in l'aggregati, anche si deve. Prublemu !

Gestisce e variabili di sessione

Allora, in a versione precedente, avemu sbattutu nantu à un puntu fundamentale - avemu bisognu à insignà di qualchì manera u trigger per distingue "i nostri" cambiamenti in a tavula da "micca u nostru". "I nostri" sò saltati cum'è, ma nantu à "micca i nostri" sò attivati. Per questu pudete aduprà variabili di sessione.

session_replication_role

Leghje manuale:

U mecanismu di trigger hè ancu affettatu da a variabile di cunfigurazione session_replication_role. Abilitatu senza struzzioni supplementari (predeterminatu), i triggers spararanu quandu u rolu di replicazione hè "origine" (default) o "local". Triggers attivati ​​da specificà ENABLE REPLICA, funzionerà solu se Modu di sessione attuale - "réplica", è triggers attivati ​​da specificà ENABLE ALWAYS, funzionerà indipendentemente da u modu di replicazione attuale.

Soprattuttu enfatizaraghju chì u paràmetru ùn hè micca appiicatu à tutti in una volta, cum'è ALTER TABLE, ma solu à a nostra cunnessione speciale separata. In totale, per chì nisuna applicazione attiva u travagliu:

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

Cundizione in u trigger

Ma l'opzione sopra funziona per tutti i triggers in una volta (o avete bisognu di "alternà" in anticipu chì ùn vulete micca disattivà). È si avemu bisognu "spegne" un trigger specificu?

Questu ci aiuterà Variabile di sessione "utente".:

I nomi di i paràmetri di l'estensione sò scritti cusì: u nome di l'estensione seguitu da un puntu è dopu u nome di u paràmetru stessu, simili à i nomi di l'ughjetti cumpleti in SQL. Per esempiu: plpgsql.variable_conflict.
Perchè l'opzioni fora di u sistema ponu esse stabilite in prucessi chì ùn caricanu micca u modulu di estensione adattatu, PostgreSQL accetta valori per qualsiasi nomi cù dui cumpunenti.

Prima, finiscemu u trigger, qualcosa cum'è questu:

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

In modu, questu pò esse fattu "per prufittu", senza bluccà, attraversu CREATE OR REPLACE per a funzione trigger. È dopu in a cunnessione speciale, cogliemu "a nostra" variabile:


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

Sapete altre manere ? Condividi in i cumenti.

Source: www.habr.com

Add a comment