Deaktivieren Sie die PostgreSQL-Fremdschlüsselprüfung für Migrationen

82

Ich erstelle viele Migrationen mit Fremdschlüsseln in PostgreSQL 9.4.

Dies verursacht Kopfschmerzen, da die Tabellen alle in der genauen Reihenfolge vorliegen müssen, die die Fremdschlüssel bei der Migration erwarten. Es wird noch schwieriger, wenn ich Migrationen von anderen Paketen ausführen muss, von denen meine neuen Migrationen für einen Fremdschlüssel abhängen.

In MySQL kann ich dies vereinfachen, indem ich einfach SET FOREIGN_KEY_CHECKS = 0;oben in meine Migrationsdatei einfüge. Wie kann ich dies vorübergehend in PostgresSQL nur für die Länge des Migrationscodes tun?

Übrigens, verwenden Sie dazu den Laravel Schema Builder.

eComEvo
quelle

Antworten:

76

PostgreSQL unterstützt keine Konfigurationsoption, es gibt jedoch eine andere Möglichkeit.

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

Die referenzielle Integrität in Postgres wird durch Trigger implementiert, und Sie können Trigger für Tabellen deaktivieren. Mit dieser Methode können Sie beliebige Daten hochladen (Risiko), diese sind jedoch erheblich schneller - da die Überprüfung großer Datenmengen teuer ist. Und wenn Ihr Upload sicher ist, können Sie es tun.

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

Die nächste Möglichkeit ist die Verwendung von verzögerten Einschränkungen. Diese Verschiebungsbeschränkungsprüfung zum Festschreiben der Zeit. Sie sollten also die Reihenfolge mit INSERTBefehlen nicht respektieren :

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

Diese Methode sollte für Sie bevorzugt werden, da die eingefügten Daten überprüft werden.

Pavel Stehule
quelle
2
Aus irgendeinem Grund hat das einmal für mich funktioniert und dann überhaupt nicht. Ich bin in aws aurora postgres, wo sie die super userRolle sperren, damit Kunden die Replikationseinstellungen nicht durcheinander bringen können. Es sieht so aus, als müsste ich ein Superuser sein, um einige Systemauslöser zu deaktivieren. (Ich verwende derzeit mein Administratorkonto, das auch der Eigentümer ist. Ich bin nicht sicher, warum es einmal funktioniert hat.) Das Festlegen der Replikationsoption ist ebenfalls keine praktikable Option, da hierfür auch die super userRolle erforderlich ist . Meine einzige Möglichkeit scheint darin zu bestehen, die Fremdschlüssel zu
löschen
Hier gilt das gleiche. DISABLE TRIGGER ALLEtwas tun , aber es hat keine Wirkung. Ich bekomme nicht einmal eine Warnung. Es wird einfach ignoriert.
Jayarjo
Auf Amazon RDS gibt dies den folgenden Fehler aus:> Berechtigung verweigert: "RI_ConstraintTrigger_a_23031" ist ein Systemauslöser, daher ist dieses Rezept leider nicht für jeden Fall :)
kolypto
147

Für die Migration ist es einfacher, alle Trigger zu deaktivieren mit:

SET session_replication_role = 'replica';

Und nach der Migration wieder mit aktivieren

SET session_replication_role = 'origin';
andro83
quelle
2
Heilige Kuh, ist dies sowohl einfacher als auch angemessener für die jeweilige Aufgabe? (Ja.)
Ijoseph
8
Achtung: Dies erfordert Superuser-Berechtigungen. Versuchen Sie "SET CONSTRAINTS ALL DEFERRED".
JJC
8
Ich bin dran 10.4und diese obige Aussage scheint nicht zu funktionieren.
Stephane
2
Wäre jemand in der Lage, die Gefahren / Risiken dieser Methode zu beschreiben und in welchen Szenarien sollte sie angewendet werden und wie Risiken gemindert werden können? Was ist die beste Vorgehensweise, wenn dies als schlechte Vorgehensweise angesehen wird?
Karns
6
Übrigens kann dieser Parameter in AWS RDS in der Datenbankparametergruppe festgelegt und angewendet werden, ohne die Datenbank neu zu starten! Sehr nützlich, wenn Sie DMS in einer leeren Datenbank mit vorhandenem Schema und erstellten Einschränkungen verwenden.
Mike Atlas