Wyłącz sprawdzanie kluczy obcych PostgreSQL dla migracji

92

Tworzę wiele migracji, które mają klucze obce w PostgreSQL 9.4.

Powoduje to ból głowy, ponieważ wszystkie tabele muszą być w dokładnie takiej kolejności, jakiej oczekują klucze obce podczas migracji. Robi się jeszcze trudniej, jeśli muszę uruchamiać migracje z innych pakietów, od których zależą moje nowe migracje dla klucza obcego.

W MySQL mogę to uprościć, dodając po prostu SET FOREIGN_KEY_CHECKS = 0;na początku mojego pliku migracji. Jak mogę to zrobić tymczasowo w PostgresSQL tylko na czas trwania kodu migracji?

BTW, używając do tego narzędzia Laravel Schema Builder.

eComEvo
źródło

Odpowiedzi:

83

PostgreSQL nie obsługuje żadnej opcji konfiguracyjnej, ale istnieje inna możliwość.

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

Integralność referencyjna w Postgres jest implementowana przez wyzwalacze i możesz wyłączyć wyzwalacze w tabeli. Dzięki tej metodzie możesz przesłać dowolne dane (ryzyko), ale jest to znacznie szybsze - ponieważ sprawdzenie dużych danych jest kosztowne. A jeśli przesyłanie jest bezpieczne, możesz to zrobić.

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

Następną możliwością jest użycie odroczonych ograniczeń. To sprawdzenie ograniczenia ruchu, aby zatwierdzić czas. Dlatego nie należy szanować porządku przy INSERTpoleceniach:

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

Ta metoda powinna być dla Ciebie preferowana, ponieważ wprowadzone dane zostaną sprawdzone.

Pavel Stehule
źródło
2
Z jakiegoś powodu raz to zadziałało, a potem wcale. Jestem w aws aurora postgres, gdzie blokują super userrolę, aby klienci nie mogli zepsuć ustawień replikacji. Wygląda na to, że muszę być superużytkownikiem, aby wyłączyć niektóre wyzwalacze systemowe. (Obecnie używam mojego konta administratora, które jest również właścicielem - nie wiem, dlaczego to kiedyś zadziałało). Ustawienie opcji replikacji również nie jest realną opcją, ponieważ również wymaga super userroli. Wydaje mi się, że jedyną opcją jest upuszczenie i odtworzenie kluczy obcych ...
ps2goat
To samo tutaj. Robię DISABLE TRIGGER ALLcoś, ale nie ma to żadnego skutku. Nie dostaję nawet żadnego ostrzeżenia. To jest po prostu ignorowane.
jayarjo
Na Amazon RDS daje to następujący błąd:> odmowa pozwolenia: "RI_ConstraintTrigger_a_23031" jest wyzwalaczem systemowym, więc ten przepis nie jest niestety dla każdego przypadku :)
kolypto
Błąd w lokalnej bazie danych. Gdy użytkownik ma wszystkie uprawnienia do bazy danych, odmówiono ** uprawnień: „RI_ConstraintTrigger_a_16564” jest wyzwalaczem systemowym **
Solo.dmitry
154

W przypadku migracji łatwiej jest wyłączyć wszystkie wyzwalacze za pomocą:

SET session_replication_role = 'replica';

A po migracji wszystko można ponownie włączyć za pomocą

SET session_replication_role = 'origin';
andro83
źródło
3
Święta krowa, czy jest to zarówno prostsze, jak i bardziej odpowiednie do konkretnego zadania. (Tak.)
ijoseph
10
Uwaga: wymaga to uprawnień superużytkownika. Spróbuj „USTAW OGRANICZENIA WSZYSTKIE ODROCZONE”.
JJC,
9
Jestem włączony 10.4i powyższe stwierdzenie nie wydaje się działać.
Stephane
2
Czy ktoś byłby w stanie nakreślić zagrożenia / ryzyka związane z tą metodą, w jakich scenariuszach należy ją stosować i jak je ograniczać? Jaka jest najlepsza praktyka, jeśli zostanie to uznane za złą praktykę?
karns
6
Przy okazji, ten parametr można ustawić w AWS RDS w grupie parametrów bazy danych i zastosować bez restartowania db! Bardzo przydatne, jeśli używasz DMS w pustej bazie danych z istniejącym schematem i utworzonymi ograniczeniami.
Mike Atlas