web-dev-qa-db-fra.com

Désactiver les contrôles de clé étrangère PostgreSQL pour les migrations

Je crée beaucoup de migrations avec des clés étrangères dans PostgreSQL 9.4.

Cela crée un casse-tête car les tables doivent toutes être dans l'ordre exact attendu par les clés étrangères lors de leur migration. Cela devient encore plus collant si je dois exécuter des migrations à partir d'autres packages sur lesquels mes nouvelles migrations dépendent pour une clé étrangère.

En MySQL, je peux simplifier cela en ajoutant simplement SET FOREIGN_KEY_CHECKS = 0; en haut de mon fichier de migration. Comment puis-je le faire temporairement dans PostgresSQL uniquement pour la longueur du code de migration?

BTW, en utilisant le Laravel Schema Builder pour cela.

39
eComEvo

PostgreSQL ne supporte aucune option de configuration, mais il existe une autre possibilité.

postgres=# \d b
        Table "public.b"
┌────────┬─────────┬───────────┐
│ Column │  Type   │ Modifiers │
╞════════╪═════════╪═══════════╡
│ id     │ integer │           │
└────────┴─────────┴───────────┘
Foreign-key constraints:
    "b_id_fkey" FOREIGN KEY (id) REFERENCES a(id) DEFERRABLE

L'intégrité référentielle dans Postgres est implémentée par des déclencheurs et vous pouvez désactiver les déclencheurs sur la table. Avec cette méthode, vous pouvez télécharger n’importe quelle donnée (risque), mais c’est beaucoup plus rapide, car la vérification de données volumineuses coûte cher. Et si votre téléchargement est sécurisé, vous pouvez le faire.

BEGIN;
ALTER TABLE b DISABLE TRIGGER ALL;
-- now the RI over table b is disabled
ALTER TABLE b ENABLE TRIGGER ALL;
COMMIT;

La possibilité suivante consiste à utiliser des contraintes différées. Cette contrainte de déplacement vérifie le temps passé. Donc, vous ne devriez pas respecter l’ordre avec les commandes INSERT:

ALTER TABLE b ALTER CONSTRAINT b_id_fkey DEFERRABLE;

BEGIN
postgres=# SET CONSTRAINTS b_id_fkey DEFERRED;
SET CONSTRAINTS
postgres=# INSERT INTO b VALUES(100); -- this is not in a table
INSERT 0 1
postgres=# INSERT INTO b VALUES(10);
INSERT 0 1 
postgres=# COMMIT;
ERROR:  insert or update on table "b" violates foreign key constraint "b_id_fkey"
DETAIL:  Key (id)=(100) is not present in table "a".

Cette méthode devrait être préférée pour vous, car les données insérées seront vérifiées.

49
Pavel Stehule

Pour la migration, il est plus facile de désactiver tous les déclencheurs avec:

SET session_replication_role = 'replica';

Et après la migration, réactivez tout avec

SET session_replication_role = 'Origin';
75
andro83