Vroeg of laat wordt iedereen geconfronteerd met de noodzaak om iets in de records van een tabel massaal te corrigeren. Ik heb al , en hoe vooral niet. Vandaag zal ik het hebben over de tweede kant van massale updates — de uitvoering van triggers..
Bijvoorbeeld, op de tabel waarin je iets moet corrigeren, hangt er een kwade trigger ON UPDATE, die alle wijzigingen naar bepaalde aggregaten verplaatst. En je moet alles bijwerken (bijvoorbeeld een nieuw veld initialiseren) op een manier die deze aggregaten niet raakt.
Laten we gewoon de triggers uitschakelen!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
UPDATE ...; -- hier duurt het lang
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;Eigenlijk is dit alles — alles hangt al.
Want ALTER TABLE legt een AccessExclusive-de vergrendeling, waaronder niemand die parallel uitgevoerd wordt, zelfs een eenvoudige SELECT, kan niets uit de tabel lezen. Dat wil zeggen, totdat deze transactie is voltooid, moeten alle geïnteresseerden zelfs "gewoon lezen" wachten. En we herinneren ons dat UPDATE we een ve-e-eel te lange…
Laten we dan snel uitschakelen, en dan snel weer inschakelen!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
COMMIT;
UPDATE ...;
BEGIN;
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;Hier is de situatie al beter, de wachttijd is aanzienlijk korter. Maar er zijn twee problemen die de hele schoonheid verpesten:
ALTER TABLEde trigger wacht op alle andere operaties op de tabel, inclusief langeSELECT- Zolang de trigger uitgeschakeld is, "ontglipt" elke wijziging in de tabel, zelfs niet onze. En het komt helemaal niet in de aggregaten, hoewel het zou moeten. Een probleem!
Beheer van sessievariabelen
Dus, in de vorige optie zijn we tegen een principieel punt aangelopen — we moeten de trigger leren om "onze" wijzigingen in de tabel te onderscheiden van "niet onze". "Onze" ongewijzigd doorlaten, en voor "niet onze" activeren. Hiervoor kunnen we gebruikmaken van .
session_replication_role
Lees meer :
Het mechanisme voor het activeren van triggers wordt ook beïnvloed door de configuratievariabele . Triggers die zonder aanvullende instructies (standaard) zijn ingeschakeld, worden geactiveerd wanneer de replicatierol — "origin" (standaard) of "local". Triggers die met de aanwijzing
ENABLE REPLICA, worden alleen geactiveerd als de huidige sessiemodus — "replica", en triggers die met de aanwijzingENABLE ALWAYS, worden geactiveerd ongeacht de huidige replicatiemodus.
Ik benadruk dat deze instelling niet voor iedereen geldt, zoals ALTER TABLE, maar alleen naar onze aparte speciale verbinding. Dus, om te voorkomen dat er enige trigger-activering is:
SET session_replication_role = replica; -- triggers uitgeschakeld
UPDATE ...;
SET session_replication_role = DEFAULT; -- in oorspronkelijke staat teruggebrachtVoorwaarde binnen de trigger
Maar de bovenstaande variant werkt voor alle triggers tegelijk (of je moet van tevoren de triggers 'alteren' die je niet wilt uitschakelen). En als we moeten één specifieke trigger "uitschakelen"?
Daarbij helpt ons :
De namen van de extensieparameters worden als volgt genoteerd: naam van de extensie, punt en dan de naam van de parameter, vergelijkbaar met de volledige namen van objecten in SQL. Bijvoorbeeld: plpgsql.variable_conflict.
Aangezien niet-systeemparameters kunnen worden ingesteld in processen die de overeenkomstige extensiemodule niet laden, accepteert PostgreSQL waarden voor elke naam met twee componenten.
Eerst werken we de trigger als volgt bij:
BEGIN
-- in het conversieproces kan alles gedaan worden
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;
... Overigens, dit kan "live" gedaan worden, zonder blokkades, via CREATE OR REPLACE voor de triggerfunctie. En dan in de speciale verbinding zetten we onze "variabele":
SET mycfg.my_table_convert_process = 'TRUE';
UPDATE ...;
SET mycfg.my_table_convert_process = ''; -- in oorspronkelijke staat teruggebracht
Ken je andere manieren? Deel ze in de opmerkingen.
Bron: habr.com
