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 CHECK
que llama a una plpgsql
función que verifica si una condición se mantiene en alguna otra tabla no relacionada. Si esa última tabla no se carga psql
antes 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_dump
no 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
-X
y-d
parapg_dump
.pg_dump
produce un volcado que se puede restaurar en una base de datos vacía.CHECK
restricción, todas las garantías se anulan, porque eso no se admite oficialmente, solo se tolera. Pero declarar laCHECK
restricción loNOT VALID
hizo funcionar para mí en todos los aspectos. Puede haber casos de esquina que nunca toqué ...Respuestas:
Entonces busca otras tablas en una
CHECK
restricción .CHECK
Se supone que las restricciones ejecutanIMMUTABLE
comprobaciones. Lo que pasa OK para una fila a la vez debe pasar OK en cualquier momento. Así es comoCHECK
se 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
CHECK
restricciones pueden usar funciones, incluso funciones definidas por el usuario. Esas deberían estar restringidas aIMMUTABLE
funciones, 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 esIMMUTABLE
por naturaleza.Pero está buscando filas de otra tabla, lo que viola por completo cómo
CHECK
se supone que funcionan las restricciones. No me sorprende quepg_dump
no 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-data
Una 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 VALID
Existe el
NOT VALID
modificador para las restricciones. Solo disponible para la restricción FK en v9.1, pero esto se extendió a lasCHECK
restricciones en 9.2. Por documentación:Un archivo de volcado simple de postgres consta de tres "secciones":
pre_data
data
post-data
Postgres 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
CHECK
restricción ofensiva aNOT VALID
, que mueve la restricción a lapost-data
secció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 VALID
restricción de verificación. Si lo prefiere, puede validarlo más tarde:Pero luego vuelves al status quo ante.
fuente
pg_dump
agrega los desencadenantes al final del archivo de volcado, mientras que crea laCHECK
s como parte delCREATE TABLE
comando. Por lo tanto, la restauración también podría haber tenido éxito para el caso de verificación si lapg_dump
herramienta 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_dump
debe 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_dump
crea el volcado. Al observar el volcado real, vi que laCHECK
restricción estaba presente en el archivo de volcado utilizando la sintaxis que forma parte delCREATE TABLE
comando: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
a
o la tablab
tengan datos. Sin embargo, si el archivo de volcado se edita yCHECK
se 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
TRIGGER
como en el siguiente script:Sin embargo, en este caso,
pg_dump
crea (de forma predeterminada) el desencadenador al final del archivo de volcado (y no en laCREATE TABLE
declaración como en el caso de una comprobación) y, por lo tanto, la restauración se realiza correctamente.fuente