PostgreSQL antipatterns: mainiet datus, apejot trigeri

Agri vai vēlu daudzi saskaras ar nepieciešamību masveidā kaut ko labot tabulas ierakstos. Es jau pastāstiet man, kā to izdarīt labāk, un kā - labāk to nedarīt. Šodien es runāšu par masu atjauninājuma otro aspektu - par trigeriem.

Piemēram, uz galda, kurā kaut kas jālabo, karājas ļauns sprūda ON UPDATE, pārnesot visas izmaiņas uz dažiem apkopojumiem. Un viss ir jāatjaunina (piemēram, jauns lauks jāinicializē) tik rūpīgi, lai šie apkopojumi netiktu ietekmēti.

Vienkārši atspējosim trigerus!

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

Patiesībā tas arī viss - viss karājas.

Jo ALTER TABLE uzliek Piekļuve ekskluzīva- slēdzene, zem kuras neviens paralēli neskrien, pat vienkārša SELECT, nevarēs neko nolasīt no tabulas. Tas ir, līdz šī darījuma beigām visi, kas vēlas pat “tikai lasīt”, gaidīs. Un mēs to atceramies UPDATE mums ir garš...

Ātri izslēgsim, tad ātri ieslēdzam!

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

UPDATE ...;

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

Šeit situācija jau ir labāka, gaidīšanas laiks ir daudz mazāks. Bet tikai divas problēmas sabojā visu skaistumu:

  • ALTER TABLE pati gaida visas pārējās darbības uz galda, arī garās SELECT
  • Kamēr sprūda ir izslēgta, "aizlidot" jebkuras izmaiņas tabulā, pat ne mūsu. Un tas neiekļūs apkopojumos, lai gan vajadzētu. Problēmas!

Sesiju mainīgo pārvaldīšana

Tātad iepriekšējā versijā mēs paklupa pie pamatjautājuma - mums kaut kā jāiemāca sprūdam atšķirt “mūsu” izmaiņas tabulā no “ne mūsu”. “Mūsējie” tiek izlaisti tā, kā tas ir, bet “ne mūsu” tie tiek aktivizēti. Šim nolūkam jūs varat izmantot sesijas mainīgie.

session_replication_role

Lasīt rokasgrāmata:

Sprūda mehānismu ietekmē arī konfigurācijas mainīgais session_replication_role. Iespējots bez papildu norādījumiem (noklusējums), aktivizētāji tiks aktivizēti, ja replikācijas loma ir “izcelsme” (noklusējums) vai “lokālā”. Trigeri iespējoti, norādot ENABLE REPLICA, darbosies tikai tad, ja pašreizējais sesijas režīms - "reprodukcija" un aktivizētāji, norādot ENABLE ALWAYS, darbosies neatkarīgi no pašreizējā replikācijas režīma.

Īpaši uzsvēršu, ka iestatījums neattiecas uz visu uzreiz, kā ALTER TABLE, bet tikai mūsu atsevišķajam īpašajam savienojumam. Kopumā, lai neviena lietojumprogrammas aktivizētājs nedarbotos:

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

Stāvoklis sprūda iekšpusē

Bet iepriekš minētā opcija darbojas visiem aktivizētājiem vienlaikus (vai arī jums ir iepriekš jāmaina aktivizētāji, kurus nevēlaties atspējot). Un ja mums vajag "izslēgt" vienu konkrētu trigeri?

Tas mums palīdzēs "lietotāja" sesijas mainīgais:

Paplašinājuma parametru nosaukumus raksta šādi: paplašinājuma nosaukums, kam seko punkts un pēc tam pats parametra nosaukums, līdzīgi kā pilniem objektu nosaukumiem SQL. Piemēram: plpgsql.variable_conflict.
Tā kā ārpussistēmas opcijas var iestatīt procesos, kas neielādē atbilstošo paplašinājuma moduli, PostgreSQL pieņem vērtības jebkuriem nosaukumiem ar diviem komponentiem.

Pirmkārt, mēs pabeidzam aktivizētāju, apmēram šādi:

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

Starp citu, to var izdarīt "peļņas nolūkos", bez bloķēšanas, cauri CREATE OR REPLACE sprūda funkcijai. Un tad īpašajā savienojumā mēs nosakām "savu" mainīgo:


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

Vai jūs zināt citus veidus? Dalieties komentāros.

Avots: www.habr.com

Pievieno komentāru