Tôt ou tard, beaucoup sont confrontés à la nécessité de corriger massivement quelque chose dans les entrées du tableau. J'ai déjà dit comment le faire mieux et comment - il vaut mieux ne pas le faire. Aujourd'hui, je vais parler du deuxième aspect de la mise à jour en masse - le déclenchement des déclencheurs .Par exemple, sur une table dans laquelle vous devez corriger quelque chose, un mauvais déclencheur se bloque ON UPDATE
, transférant toutes les modifications à certains agrégats. Et vous devez tout mettre à jour (initialiser un nouveau champ, par exemple) si soigneusement que ces unités ne sont pas affectées.Disons simplement désactiver les déclencheurs!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
UPDATE ...;
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;
En fait, c'est tout - tout est déjà suspendu .Parce qu'il ALTER TABLE
impose un verrou AccessExclusive , sous lequel personne ne s'exécutant en parallèle, même un simple SELECT
, ne peut rien lire de la table. Autrement dit, jusqu'à ce que cette transaction soit terminée, tous ceux qui veulent «simplement lire» attendront. Et nous nous souvenons que UPDATE
nous do-o-olgi ...Arrêtons-le rapidement, puis rallumons-le rapidement!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
COMMIT;
UPDATE ...;
BEGIN;
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;
Ici, la situation est meilleure, le temps d'attente est beaucoup plus court. Mais seulement deux problèmes gâchent toute la beauté:ALTER TABLE
il attend toutes les autres opérations sur la table, y compris les longues SELECT
- Tant que la gâchette est désactivée, tout changement dans la table passera , pas même le nôtre. Et bien, il n'entrera pas dans les unités, bien qu'il le devrait. Difficulté!
Gestion des variables de session
Ainsi, dans la version précédente, nous sommes tombés sur un point crucial - nous devons en quelque sorte enseigner le déclencheur pour distinguer «nos» changements dans le tableau de «pas les nôtres». Ignorez «le nôtre» tel quel, mais «pas le nôtre» - déclencheur. Vous pouvez utiliser des variables de session pour cela .session_replication_role
Lisez le manuel :La variable de déclenchement est également affectée par la variable de configuration session_replication_role . Les déclencheurs activés sans instructions supplémentaires (par défaut) se déclenchent lorsque le rôle de réplication est «origine» (par défaut) ou «local». Les déclencheurs activés par une indication ENABLE REPLICA
ne se déclencheront que si le mode de session actuel est "réplique", et les déclencheurs activés par une indication ENABLE ALWAYS
se déclencheront quel que soit le mode de réplication actuel.
J'insiste sur le fait que la configuration ne s'applique pas à tout à la fois, car ALTER TABLE
, mais seulement à notre connexion spéciale séparée. Total pour qu'aucune application ne déclenche le feu:SET session_replication_role = replica;
UPDATE ...;
SET session_replication_role = DEFAULT;
Condition à l'intérieur de la gâchette
Mais l'option ci-dessus fonctionne pour tous les déclencheurs à la fois (ou vous devez «déclencher» à l'avance des déclencheurs que vous ne voulez pas désactiver). Et si nous devons "désactiver" un déclencheur spécifique ?La variable de session «utilisateur» nous aidera avec ceci :Les noms des paramètres d'extension sont écrits comme suit: nom de l'extension, point, puis le nom du paramètre lui-même, comme les noms complets des objets dans SQL. Par exemple: plpgsql.variable_conflict.
Étant donné que les paramètres non système peuvent être définis dans des processus qui ne chargent pas le module d'extension correspondant, PostgreSQL accepte les valeurs de tous les noms à deux composants .
Tout d'abord, modifiez le déclencheur, quelque chose comme ceci: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;
...
Soit dit en passant, cela peut être fait "de manière rentable", sans verrouillage, grâce CREATE OR REPLACE
à une fonction de déclenchement. Et puis dans la connexion spéciale, nous armons "notre" variable:
SET mycfg.my_table_convert_process = 'TRUE';
UPDATE ...;
SET mycfg.my_table_convert_process = '';
Connaissez-vous d'autres moyens? Partagez dans les commentaires.