Deshabilitar las comprobaciones de claves foráneas de PostgreSQL para migraciones

82

Estoy creando muchas migraciones que tienen claves externas en PostgreSQL 9.4.

Esto crea un dolor de cabeza porque las tablas deben estar todas en el orden exacto esperado por las claves externas cuando se migran. Se vuelve aún más complicado si tengo que ejecutar migraciones desde otros paquetes de los que dependen mis nuevas migraciones para obtener una clave externa.

En MySQL, puedo simplificar esto simplemente agregando SET FOREIGN_KEY_CHECKS = 0;a la parte superior de mi archivo de migración. ¿Cómo puedo hacer esto temporalmente en PostgresSQL solo por la longitud del código de migración?

Por cierto, usando el generador de esquemas de Laravel para esto.

eComEvo
fuente

Respuestas:

76

PostgreSQL no admite ninguna opción de configuración, pero existe otra posibilidad.

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

La integridad referencial en Postgres se implementa mediante desencadenadores, y puede deshabilitar los desencadenantes en la tabla. Con este método puede cargar cualquier dato (riesgo), pero es significativamente más rápido, porque la verificación de datos grandes es costosa. Y si su carga es segura, entonces puede hacerlo.

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

La siguiente posibilidad es utilizar restricciones diferidas. Esta comprobación de restricción de movimiento para comprometer el tiempo. Por lo que no debes respetar el orden con los INSERTcomandos:

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

Este método debería ser el preferido para usted, porque se comprobarán los datos insertados.

Pavel Stehule
fuente
2
Por alguna razón, esto funcionó una vez para mí y luego no en absoluto. Estoy en aws aurora postgres, donde bloquean el super userrol para que los clientes no puedan estropear la configuración de replicación. Parece que tengo que ser un superusuario para desactivar algunos activadores del sistema. (Actualmente estoy usando mi cuenta de administrador que también es la propietaria; no estoy seguro de por qué funcionó una vez). Establecer la opción de replicación tampoco es una opción viable, ya que también requiere el super userrol. Mi única opción parece ser soltar y recrear las claves externas ...
ps2goat
Igual que aquí. Haciendo DISABLE TRIGGER ALLalgo, pero no tiene ningún efecto. Ni siquiera recibo ninguna advertencia. Simplemente se ignora.
jayarjo
En Amazon RDS, esto da el siguiente error:> permiso denegado: "RI_ConstraintTrigger_a_23031" es un activador del sistema, por lo que esta receta no es para todos los casos, desafortunadamente :)
kolypto
147

Para la migración, es más fácil deshabilitar todos los activadores con:

SET session_replication_role = 'replica';

Y después de la migración, vuelva a habilitarlo todo con

SET session_replication_role = 'origin';
andro83
fuente
2
Santo cielo, ¿es esto más simple y más apropiado para la tarea específica en cuestión? (Sí.)
ijoseph
8
Advertencia: esto requiere privilegios de superusuario. Prueba "ESTABLECER RESTRICCIONES TODAS DIFERIDAS".
JJC
8
Estoy encendido 10.4y esta declaración anterior no parece funcionar.
Stephane
2
¿Alguien podría describir los peligros / riesgos de este método y en qué escenarios debería usarse y cómo mitigar los riesgos? ¿Cuál es la mejor práctica si esto se considera una mala práctica?
karns
6
Por cierto, este parámetro puede configurarse en AWS RDS en el grupo de parámetros de la base de datos y aplicarse sin reiniciar la base de datos. Muy útil si está utilizando DMS en una base de datos vacía con el esquema existente y las restricciones creadas.
Mike Atlas