PostgreSQL Antimönster: ändra data förbi en trigger

Förr eller senare ställs många människor inför behovet av att massivt korrigera något i tabellposter. jag har redan berätta för mig hur man gör det bättre, och hur - det är bättre att inte göra det. Idag kommer jag att prata om den andra aspekten av massuppdateringen - om triggers.

Till exempel, på ett bord där du behöver korrigera något, finns det en ond trigger ON UPDATE, överför alla ändringar till vissa aggregat. Och du måste uppdatera allt (initiera ett nytt fält till exempel) så noggrant att dessa enheter inte påverkas.

Låt oss bara stänga av triggers!

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

Egentligen är det allt - allt hänger.

Eftersom ALTER TABLE ålägger Exklusiv tillgång- ett lås under vilket ingen springer parallellt, inte ens ett enkelt sådant SELECT, kommer inte att kunna läsa något från tabellen. Det vill säga, tills denna transaktion är slutförd kommer alla som ens vill "bara läsa" att vänta. Och det minns vi UPDATE vi har en lång...

Låt oss snabbt stänga av den och sedan snabbt slå på den!

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

UPDATE ...;

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

Här är läget redan bättre, väntetiden är mycket kortare. Men bara två problem förstör all skönhet:

  • ALTER TABLE själv väntar på alla andra operationer på bordet, inklusive långa SELECT
  • Medan avtryckaren är avstängd alla förändringar kommer att "flyga förbi" i tabellen, inte ens vår. Och det kommer inte in i aggregaten, även om det borde. Problem!

Hantera sessionsvariabler

Så i den tidigare versionen stötte vi på en grundläggande punkt - vi måste på något sätt lära utlösaren att skilja "våra" ändringar i tabellen från "inte våra". "Vårt" hoppas över som det är och "inte vårt" utlöses. För detta kan du använda sessionsvariabler.

session_replikeringsroll

läs manuell:

Utlösningsmekanismen påverkas också av konfigurationsvariabeln session_replikeringsroll. När den är aktiverad utan ytterligare instruktioner (standard), aktiveras utlösare när replikeringsrollen är "ursprung" (standard) eller "lokal". Utlösare aktiveras genom att specificera ENABLE REPLICA, fungerar bara om nuvarande sessionsläge - "replika" och triggers aktiveras genom att specificera ENABLE ALWAYS, kommer att fungera oavsett det aktuella replikeringsläget.

Jag vill särskilt betona att inställningen inte gäller alla på en gång, som ALTER TABLE, men bara till vår separata speciella anslutning. Totalt, så att inga programutlösare fungerar:

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

Tillstånd inuti en avtryckare

Men alternativet ovan fungerar för alla utlösare samtidigt (eller så måste du "ändra" i förväg de utlösare som du inte vill inaktivera). Och om vi behöver "stänga av" en specifik trigger?

Detta kommer att hjälpa oss sessionsvariabel "användare".:

Tilläggsparameternamn skrivs enligt följande: tilläggsnamn, punkt och sedan själva parameternamnet, liknande fullständigt kvalificerade objektnamn i SQL. Till exempel: plpgsql.variable_conflict.
Eftersom icke-systemalternativ kan ställas in i processer som inte laddar motsvarande tilläggsmodul, accepterar PostgreSQL värden för alla namn med två komponenter.

Först slutför vi triggern, ungefär så här:

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

Detta kan förresten göras "för vinst", utan att blockera, igenom CREATE OR REPLACE för triggerfunktionen. Och sedan, i den speciella anslutningen, kopplar vi "vår" variabel:


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

Vet du andra sätt? Dela i kommentarerna.

Källa: will.com

Lägg en kommentar