Prije ili kasnije, mnogi se susreću s potrebom da se nešto masovno popravi u tabličnim zapisima. Već jesam reci mi kako da to bolje uradim, a kako - bolje je ne raditi. Danas ću govoriti o drugom aspektu masovnog ažuriranja - o okidačima.
Na primjer, na stolu u kojem trebate nešto popraviti, visi zao okidač ON UPDATE, prenoseći sve promjene na neke agregate. I treba da ažurirate sve (na primjer, inicijalizirate novo polje) tako pažljivo da to ne utiče na ove agregate.
Hajde da samo onemogućimo okidače!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
UPDATE ...; -- тут долго-долго
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;
Zapravo, to je sve - sve visi.
Jer ALTER TABLE nameće Pristup ekskluzivno- brava ispod koje niko ne trči paralelno, čak ni obična SELECT, neće moći pročitati ništa sa tabele. Odnosno, dok se ova transakcija ne završi, svi koji žele čak i „samo da čitaju“ čekaće. I sećamo se toga UPDATE imamo dugo...
Brzo ga ugasimo, pa brzo upalimo!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
COMMIT;
UPDATE ...;
BEGIN;
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;
Ovdje je situacija već bolja, vrijeme čekanja je znatno manje. Ali samo dva problema kvare svu ljepotu:
ALTER TABLE sama čeka na sve ostale operacije na stolu, uključujući i duge SELECT
Dok je okidač isključen "proleti" bilo koju promjenu u tabeli, čak ni naš. I neće ući u agregate, iako bi trebalo. Nevolja!
Upravljanje varijablama sesije
Dakle, u prethodnoj verziji naišli smo na fundamentalnu stvar - moramo nekako naučiti okidač da razlikuje „naše“ promjene u tabeli od „ne naših“. “Naši” se preskaču kao što jesu, ali na “ne naš” se aktiviraju. Za ovo možete koristiti varijable sesije.
Na mehanizam okidača također utiče konfiguracijska varijabla session_replication_role. Omogućeno bez dodatnih instrukcija (podrazumevano), okidači će se aktivirati kada je uloga replikacije "origin" (podrazumevano) ili "local". Okidači su omogućeni navođenjem ENABLE REPLICA, radiće samo ako režim trenutne sesije - "replika", i okidači omogućeni navođenjem ENABLE ALWAYS, radit će bez obzira na trenutni način replikacije.
Posebno ću naglasiti da se postavka ne odnosi na sve-sve odjednom, kao ALTER TABLE, ali samo na našu posebnu posebnu vezu. Ukupno, tako da nijedan okidač aplikacije ne radi:
SET session_replication_role = replica; -- выключили триггеры
UPDATE ...;
SET session_replication_role = DEFAULT; -- вернули в исходное состояние
Stanje unutar okidača
Ali gornja opcija radi za sve okidače odjednom (ili morate unaprijed "alternirati" okidače koje ne želite onemogućiti). I ako nam zatreba "isključi" jedan određeni okidač?
Imena parametara ekstenzije pišu se na sljedeći način: ime ekstenzije praćeno točkom, a zatim samo ime parametra, slično punim imenima objekata u SQL-u. Na primjer: plpgsql.varijable_conflict.
Budući da se opcije izvan sistema mogu postaviti u procesima koji ne učitavaju odgovarajući modul proširenja, PostgreSQL prihvata vrijednosti za bilo koja imena sa dvije komponente.
Prvo, finaliziramo okidač, otprilike ovako:
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;
...
Usput, to se može učiniti "za profit", bez blokiranja, kroz CREATE OR REPLACE za funkciju okidača. A onda u posebnoj vezi ubacujemo "našu" varijablu:
SET mycfg.my_table_convert_process = 'TRUE';
UPDATE ...;
SET mycfg.my_table_convert_process = ''; -- вернули в исходное состояние