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.
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?
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 = ''; -- вернули в исходное состояние