PostgreSQL Antipatterns: ŝanĝi datumojn preterpasante ellasilon

Pli aŭ malpli frue, multaj alfrontas la bezonon amase fiksi ion en la tabelaj registroj. mi jam havas diru al mi kiel fari ĝin pli bone, kaj kiel - estas pli bone ne fari ĝin. Hodiaŭ mi parolos pri la dua aspekto de la amasa ĝisdatigo - pri ellasiloj.

Ekzemple, sur tablo, en kiu vi bezonas ion ripari, pendas malbona ellasilo ON UPDATE, transdonante ĉiujn ŝanĝojn al kelkaj agregaĵoj. Kaj vi devas ĝisdatigi ĉion (komencigi novan kampon, ekzemple) tiel zorge, ke ĉi tiuj agregaĵoj ne estas tuŝitaj.

Ni simple malŝaltu la ellasilon!

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

Fakte, jen ĉio - ĉio pendas.

Ĉar ALTER TABLE trudas Aliro Ekskluziva- seruro, sub kiu neniu kuras paralele, eĉ simpla SELECT, nenion povos legi el la tablo. Tio estas, ĝis ĉi tiu transakcio finiĝos, ĉiuj, kiuj volas eĉ "nur legi", atendos. Kaj ni memoras tion UPDATE ni havas longan...

Ni rapide malŝaltu ĝin, poste rapide ŝaltu ĝin!

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

UPDATE ...;

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

Ĉi tie la situacio jam estas pli bona, la atendotempo estas multe malpli. Sed nur du problemoj difektas la tutan belecon:

  • ALTER TABLE mem atendas ĉiujn aliajn operaciojn sur la tablo, inkluzive de longaj SELECT
  • Dum la ellasilo estas malŝaltita "flugi preter" ajna ŝanĝo en la tablo, eĉ ne la nia. Kaj ĝi ne eniros en la agregaĵojn, kvankam ĝi devus. Problemo!

Administri seancaj variabloj

Do, en la antaŭa versio, ni trovis fundamentan punkton - ni devas iel instrui la ellasilon distingi "niajn" ŝanĝojn en la tabelo de "ne nia". "Niaj" estas preterlasitaj kiel estas, sed ĉe "ne nia" ili estas ekigitaj. Por tio vi povas uzi seancaj variabloj.

sesio_replica_rolo

Legado manlibro:

La ellasilmekanismo ankaŭ estas trafita per la agorda variablo sesio_replica_rolo. Ebligita sen pliaj instrukcioj (defaŭlte), ellasiloj ekfunkciiĝos kiam la reprodukta rolo estas "devena" (defaŭlte) aŭ "loka". Ellasiloj ebligitaj per specifo ENABLE REPLICA, funkcios nur se nuna seanca reĝimo - "repliko", kaj ellasiloj ebligitaj per specifado ENABLE ALWAYS, funkcios sendepende de la nuna reprodukta reĝimo.

Mi precipe emfazos, ke la agordo ne validas por ĉio-ĉio samtempe, kiel ALTER TABLE, sed nur al nia aparta speciala ligo. Entute, por ke neniu aplikaĵo ekfunkciigu:

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

Kondiĉo ene de ellasilo

Sed la supra opcio funkcias por ĉiuj ellasiloj samtempe (aŭ vi devas "alterni" ellasilon anticipe, kiujn vi ne volas malŝalti). Kaj se ni bezonas "malŝalti" unu specifan ellasilon?

Ĉi tio helpos nin "uzanto" seanca variablo:

Etendaj parametronomoj estas skribitaj jene: la etenda nomo sekvata de punkto kaj tiam la parametronomo mem, simile al plenaj objektonomoj en SQL. Ekzemple: plpgsql.variable_conflict.
Ĉar ekster-sistemaj opcioj povas esti agorditaj en procezoj kiuj ne ŝarĝas la taŭgan etendomodulon, PostgreSQL akceptas valoroj por iuj nomoj kun du komponantoj.

Unue, ni finas la ellasilon, io kiel ĉi tio:

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

Cetere, ĉi tio povas esti farita "por profito", sen blokado, tra CREATE OR REPLACE por la ellasilfunkcio. Kaj tiam en la speciala konekto ni ĉasas "nian" variablon:


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

Ĉu vi konas aliajn manierojn? Kunhavigu en la komentoj.

fonto: www.habr.com

Aldoni komenton