PostgreSQL Antipatterns: muuta dataa ohittamalla liipaisimen

Ennemmin tai myöhemmin monet kohtaavat tarpeen korjata massiivisesti jotain taulukon tietueissa. Minulla on jo kerro kuinka se tehdään paremmin, ja miten - on parempi olla tekemättä sitä. Tänään puhun massapäivityksen toisesta näkökulmasta - triggereistä.

Esimerkiksi pöydällä, jossa sinun on korjattava jotain, paha laukaisu roikkuu ON UPDATE, siirtää kaikki muutokset joihinkin aggregaatteihin. Ja sinun on päivitettävä kaikki (esimerkiksi alustettava uusi kenttä) niin huolellisesti, ettei se vaikuta näihin aggregaatteihin.

Laitetaanpa laukaisimet pois päältä!

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

Itse asiassa, siinä kaikki - kaikki roikkuu.

Koska ALTER TABLE määrää Access Exclusive- lukko, jonka alla kukaan ei juokse rinnakkain, edes yksinkertainen SELECT, ei voi lukea mitään taulukosta. Eli kunnes tämä tapahtuma päättyy, kaikki, jotka haluavat jopa "vain lukea", odottavat. Ja me muistamme sen UPDATE meillä on pitkä...

Sammuta se nopeasti ja käynnistä se sitten nopeasti!

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

UPDATE ...;

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

Täällä tilanne on jo parempi, odotusaika on paljon lyhyempi. Mutta vain kaksi ongelmaa pilaa kaiken kauneuden:

  • ALTER TABLE itse odottaa kaikkia muita toimintoja pöydällä, mukaan lukien pitkät SELECT
  • Kun liipaisin on pois päältä, "lentää ohi" mitään muutosta taulukossa, ei edes meidän. Ja se ei pääse aggregaatteihin, vaikka sen pitäisi. Ongelmia!

Istuntomuuttujien hallinta

Joten edellisessä versiossa törmäsimme perustavanlaatuiseen asiaan - meidän on jotenkin opetettava laukaisin erottamaan taulukon "meidän" muutokset "ei meidän". "Meidän" ohitetaan sellaisenaan, mutta "ei meidän" kohdalla ne laukeavat. Tätä varten voit käyttää istunnon muuttujat.

session_replication_role

luettu manuaalinen:

Liipaisumekanismiin vaikuttaa myös konfiguraatiomuuttuja session_replication_role. Käytössä ilman lisäohjeita (oletus), triggerit käynnistyvät, kun replikointirooli on "alkuperä" (oletus) tai "paikallinen". Triggerit otetaan käyttöön määrittämällä ENABLE REPLICA, toimii vain jos nykyinen istuntotila - "replica" ja liipaisimet otetaan käyttöön määrittämällä ENABLE ALWAYS, toimii nykyisestä replikointitilasta riippumatta.

Korostan erityisesti, että asetus ei koske kaikkia kerralla, kuten ALTER TABLE, mutta vain erilliseen erikoisliitäntäämme. Yhteensä, jotta mikään sovelluslaukaisu ei toimi:

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

Kunto liipaisimen sisällä

Mutta yllä oleva vaihtoehto toimii kaikille laukaisuille kerralla (tai sinun on "vaihdetettava" liipaisimet etukäteen, joita et halua poistaa käytöstä). Ja jos tarvitsemme "sammuta" yksi tietty liipaisin?

Tämä auttaa meitä "user" istuntomuuttuja:

Laajennusparametrien nimet kirjoitetaan seuraavasti: laajennuksen nimi, jota seuraa piste ja sitten itse parametrin nimi, joka on samanlainen kuin täydet objektien nimet SQL:ssä. Esimerkiksi: plpgsql.variable_conflict.
Koska järjestelmän ulkopuoliset asetukset voidaan asettaa prosesseihin, jotka eivät lataa asianmukaista laajennusmoduulia, PostgreSQL hyväksyy sen arvot kaikille nimille, joissa on kaksi komponenttia.

Ensin viimeistelemme liipaisimen, jotenkin näin:

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

Muuten, tämä voidaan tehdä "voittoa varten", ilman estoa, kautta CREATE OR REPLACE laukaisutoimintoa varten. Ja sitten erityisessä yhteydessä valitsemme "meidän" muuttujamme:


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

Tiedätkö muita tapoja? Jaa kommenteissa.

Lähde: will.com

Lisää kommentti