He obtenido un volcado de mi base de datos PostgreSQL con:
pg_dump -U user-name -d db-name -f dumpfile
que luego procedo a restaurar en otra base de datos con:
psql X -U postgres -d db-name-b -f dumpfile
Mi problema es que la base de datos contiene restricciones referenciales, comprobaciones y disparadores y algunos de estos (comprobaciones que parecerían en particular) fallan durante la restauración, ya que la información no se carga en el orden que haría que se respetaran esas comprobaciones. Por ejemplo, insertar una fila en una tabla puede estar asociado con un CHECKque llama a una plpgsqlfunción que verifica si una condición se mantiene en alguna otra tabla no relacionada. Si esa última tabla no se carga psqlantes que la anterior, se produce un error.
El siguiente es un SSCCE que produce una base de datos de este tipo que una vez vertida pg_dumpno se puede restaurar:
CREATE OR REPLACE FUNCTION fail_if_b_empty () RETURNS BOOLEAN AS $$
SELECT EXISTS (SELECT 1 FROM b)
$$ LANGUAGE SQL;
CREATE TABLE IF NOT EXISTS a (
i INTEGER NOT NULL
);
INSERT INTO a(i) VALUES (0),(1);
CREATE TABLE IF NOT EXISTS b (
i INTEGER NOT NULL
);
INSERT INTO b(i) VALUES (0);
ALTER TABLE a ADD CONSTRAINT a_constr_1 CHECK (fail_if_b_empty());
¿Hay alguna manera de deshabilitar (desde la línea de comando) todas esas restricciones durante la restauración del volcado y habilitarlas nuevamente nuevamente después? Estoy ejecutando PostgreSQL 9.1.
fuente

-Xy-dparapg_dump.pg_dumpproduce un volcado que se puede restaurar en una base de datos vacía.CHECKrestricción, todas las garantías se anulan, porque eso no se admite oficialmente, solo se tolera. Pero declarar laCHECKrestricción loNOT VALIDhizo funcionar para mí en todos los aspectos. Puede haber casos de esquina que nunca toqué ...Respuestas:
Entonces busca otras tablas en una
CHECKrestricción .CHECKSe supone que las restricciones ejecutanIMMUTABLEcomprobaciones. Lo que pasa OK para una fila a la vez debe pasar OK en cualquier momento. Así es comoCHECKse definen las restricciones en el estándar SQL. Esa es también la razón de esta restricción ( según la documentación ):Ahora, las expresiones en
CHECKrestricciones pueden usar funciones, incluso funciones definidas por el usuario. Esas deberían estar restringidas aIMMUTABLEfunciones, pero Postgres actualmente no aplica esto. De acuerdo con esta discusión relacionada sobre pgsql-hackers , una razón es permitir referencias a la hora actual, que no esIMMUTABLEpor naturaleza.Pero está buscando filas de otra tabla, lo que viola por completo cómo
CHECKse supone que funcionan las restricciones. No me sorprende quepg_dumpno pueda prever esto.Mueva su cheque en otra tabla a un disparador (que es la herramienta correcta), y debería funcionar con versiones modernas de Postgres.
PostgreSQL 9.2 o posterior
Si bien lo anterior es cierto para cualquier versión de Postgres, se han introducido varias herramientas con Postgres 9.2 para ayudar con su situación:
Opción pg_dump
--exclude-table-dataUna solución simple sería volcar el db sin datos para la tabla infractora con:
Luego agregue solo los datos para esta tabla al final del volcado con:
Pero pueden surgir complicaciones con otras restricciones en la misma tabla. Hay una solución aún mejor :
NOT VALIDExiste el
NOT VALIDmodificador para las restricciones. Solo disponible para la restricción FK en v9.1, pero esto se extendió a lasCHECKrestricciones en 9.2. Por documentación:Un archivo de volcado simple de postgres consta de tres "secciones":
pre_datadatapost-dataPostgres 9.2 también introdujo una opción para volcar secciones por separado
-- section=sectionname, pero eso no ayuda con el problema en cuestión.Aquí es donde se pone interesante. Por documentación:
El énfasis en negrita es mío.
Puede cambiar la
CHECKrestricción ofensiva aNOT VALID, que mueve la restricción a lapost-datasección. Suelta y recrea:Esto debería solucionar tu problema. Incluso puede dejar la restricción en ese estado , ya que eso refleja mejor lo que realmente hace: verificar nuevas filas, pero no ofrece garantías para los datos existentes. No hay nada malo con una
NOT VALIDrestricción de verificación. Si lo prefiere, puede validarlo más tarde:Pero luego vuelves al status quo ante.
fuente
pg_dumpagrega los desencadenantes al final del archivo de volcado, mientras que crea laCHECKs como parte delCREATE TABLEcomando. Por lo tanto, la restauración también podría haber tenido éxito para el caso de verificación si lapg_dumpherramienta utilizara un enfoque diferente. No entiendo por qué mi DDL está bien si uso desencadenantes, pero no está bien si uso comprobaciones ya que se implementa exactamente la misma lógica en ambos casos (puede ver la versión del script que usa desencadenantes en mi propia respuesta).pg_dumpdebe generar diferentes DDL para verificar las restricciones (por ejemplo, agregarlas todas al final), debe publicarlo en la lista de correo de Postgres como una solicitud de mejora. Pero sí estoy de acuerdo con Erwin en que estás usando mal las restricciones de verificación para algo para lo que no fueron diseñadas. Por lo tanto, no esperaría que esa solicitud de cambio se implemente en un futuro próximo. Por cierto: su SSCCE se modelaría mejor usando una clave foránea entre las dos tablas.Parece que esto se debe a la forma en que
pg_dumpcrea el volcado. Al observar el volcado real, vi que laCHECKrestricción estaba presente en el archivo de volcado utilizando la sintaxis que forma parte delCREATE TABLEcomando:Esto crea la falla tras la restauración de la base de datos, ya que la verificación se realiza antes de que la tabla
ao la tablabtengan datos. Sin embargo, si el archivo de volcado se edita yCHECKse agrega utilizando la siguiente sintaxis, al final del archivo de volcado:... entonces no hay problema en la restauración.
La misma lógica exacta se puede implementar usando un
TRIGGERcomo en el siguiente script:Sin embargo, en este caso,
pg_dumpcrea (de forma predeterminada) el desencadenador al final del archivo de volcado (y no en laCREATE TABLEdeclaración como en el caso de una comprobación) y, por lo tanto, la restauración se realiza correctamente.fuente