J'ai obtenu un vidage de ma base de données PostgreSQL avec:
pg_dump -U user-name -d db-name -f dumpfile
que je procède ensuite à restaurer dans une autre base de données avec:
psql X -U postgres -d db-name-b -f dumpfile
Mon problème est que la base de données contient des contraintes référentielles, des vérifications et des déclencheurs et certains de ces contrôles (il semblerait en particulier) échouent pendant la restauration car les informations ne sont pas chargées dans l'ordre qui entraînerait le respect de ces vérifications. Par exemple, l' insertion d' une ligne dans une table peut être associée à un CHECK
qui appelle une plpgsql
fonction qui vérifie si une condition est dans une autre table sans rapport. Si cette dernière table n'est pas chargée par psql
avant la première, une erreur se produit.
Ce qui suit est un SSCCE qui produit une telle base de données qui, une fois sauvegardée avec, pg_dump
ne peut pas être restaurée:
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());
Existe-t-il un moyen de désactiver (à partir de la ligne de commande) toutes ces contraintes pendant la restauration du vidage et de les réactiver par la suite? J'utilise PostgreSQL 9.1.
la source
-X
et d'-d
options pourpg_dump
.pg_dump
produit un vidage qui peut être restauré dans une base de données vide.CHECK
contrainte, alors toutes les garanties sont annulées, car ce n'est pas officiellement pris en charge, juste toléré. Mais déclarer laCHECK
contrainte l'aNOT VALID
fait fonctionner à tous égards pour moi. Il y a peut-être des cas d'angle que je n'ai jamais touchés ...Réponses:
Vous recherchez donc d'autres tables dans une
CHECK
contrainte .CHECK
les contraintes sont censées exécuter desIMMUTABLE
vérifications. Ce qui passe OK pour une rangée à la fois devrait passer OK à tout moment. C'est ainsi que lesCHECK
contraintes sont définies dans le standard SQL. C'est aussi la raison de cette restriction ( selon la documentation ):Désormais, les expressions dans les
CHECK
contraintes sont autorisées à utiliser des fonctions, même des fonctions définies par l'utilisateur. Ceux-ci devraient être limités auxIMMUTABLE
fonctions, mais Postgres ne les applique pas actuellement. Selon cette discussion connexe sur les hackers pgsql , une des raisons est de permettre les références à l'heure actuelle, qui n'est pasIMMUTABLE
par nature.Mais vous recherchez des lignes d'une autre table, ce qui est complètement en violation de la façon dont les
CHECK
contraintes sont censées fonctionner. Je ne suis pas surpris que celapg_dump
ne prévoie pas cela.Déplacez votre chèque dans une autre table vers un déclencheur (qui est le bon outil), et cela devrait fonctionner avec les versions modernes de Postgres.
PostgreSQL 9.2 ou version ultérieure
Bien que ce qui précède soit vrai pour n'importe quelle version de Postgres, plusieurs outils ont été introduits avec Postgres 9.2 pour vous aider dans votre situation:
Option pg_dump
--exclude-table-data
Une solution simple serait de vider la base de données sans données pour la table violée avec:
Ajoutez ensuite uniquement les données de ce tableau à la fin du vidage avec:
Mais des complications avec d'autres contraintes sur la même table pourraient en résulter. Il existe une solution encore meilleure :
NOT VALID
Il y a le
NOT VALID
modificateur pour les contraintes. Disponible uniquement pour la contrainte FK dans la v9.1, mais cela a été étendu auxCHECK
contraintes dans 9.2.Par documentation:Un fichier de vidage postgres simple se compose de trois "sections":
pre_data
data
post-data
Postgres 9.2 a également introduit une option pour vider les sections séparément avec
-- section=sectionname
, mais cela ne résout pas le problème actuel.Voici où cela devient intéressant. Par documentation:
Accentuation mienne.
Vous pouvez remplacer la
CHECK
contrainte incriminée parNOT VALID
, ce qui déplace la contrainte vers lapost-data
section. Déposer et recréer:Cela devrait résoudre votre problème. Vous pouvez même laisser la contrainte dans cet état , car cela reflète mieux ce qu'elle fait réellement: vérifiez les nouvelles lignes, mais ne donnez aucune garantie pour les données existantes. Il n'y a rien de mal à une
NOT VALID
contrainte de vérification. Si vous préférez, vous pouvez le valider plus tard:Mais vous revenez au statu quo ante.
la source
pg_dump
ajout des déclencheurs à la fin du fichier de vidage, alors qu'il crée leCHECK
s dans le cadre de laCREATE TABLE
commande. La restauration aurait donc pu également réussir pour le cas de vérification si l'pg_dump
outil avait utilisé une approche différente. Je ne vois pas pourquoi mon DDL est OK si j'utilise des déclencheurs mais pas OK si j'utilise des vérifications car la même logique exacte est implémentée dans les deux cas (vous pouvez voir la version du script utilisant des déclencheurs dans ma propre réponse).pg_dump
générer un DDL différent pour les contraintes de vérification (par exemple, en les ajoutant toutes à la fin), vous devez le publier sur la liste de diffusion Postgres en tant que demande d'amélioration. Mais je suis d'accord avec Erwin que vous utilisez mal les contraintes de vérification pour quelque chose pour lequel elles n'ont pas été conçues. Je ne m'attendrais donc pas à ce que cette demande de changement soit mise en œuvre dans un avenir proche. Btw: votre SSCCE serait mieux modélisé en utilisant une clé étrangère entre les deux tables.Il semble que cela soit dû à la façon dont
pg_dump
crée le vidage. En regardant le vidage réel, j'ai vu que laCHECK
contrainte était présente dans le fichier de vidage en utilisant la syntaxe qui fait partie de laCREATE TABLE
commande:Cela crée l'échec lors de la restauration de la base de données car la vérification est mise en place avant que la table
a
ou la tableb
contiennent des données. Si toutefois, le fichier de vidage est modifié etCHECK
est ajouté à l'aide de la syntaxe suivante à la fin du fichier de vidage:... alors il n'y a pas de problème dans la restauration.
La même logique exacte peut être implémentée à l'aide de a
TRIGGER
comme dans le script suivant:Dans ce cas cependant,
pg_dump
crée (par défaut) le déclencheur à la fin du fichier de vidage (et non dans l'CREATE TABLE
instruction comme dans le cas d'une vérification) et ainsi la restauration réussit.la source