it-swarm.com.de

Deaktivieren Sie alle Einschränkungen und Tabellenprüfungen, während Sie einen Speicherauszug wiederherstellen

Ich habe einen Speicherauszug meiner PostgreSQL-Datenbank erhalten mit:

pg_dump -U user-name -d db-name -f dumpfile

die ich dann in einer anderen Datenbank wiederherstelle mit:

psql X -U postgres  -d db-name-b -f dumpfile

Mein Problem ist, dass die Datenbank referenzielle Einschränkungen, Überprüfungen und Auslöser enthält und einige dieser (insbesondere Überprüfungen) während der Wiederherstellung fehlschlagen, da die Informationen nicht in der Reihenfolge geladen werden, in der diese Überprüfungen berücksichtigt werden. Zum Beispiel kann das Einfügen einer Zeile in eine Tabelle mit einer CHECK verknüpft sein, die eine plpgsql -Funktion aufruft, die prüft, ob eine Bedingung in einer anderen nicht verwandten Tabelle gilt. Wenn diese letztere Tabelle nicht vor der ersteren von psql geladen wird, tritt ein Fehler auf.

Das Folgende ist eine SSCCE, die eine solche Datenbank erzeugt, die einmal mit pg_dump kann nicht wiederhergestellt werden:

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());

Gibt es eine Möglichkeit, alle derartigen Einschränkungen während der Dump-Wiederherstellung (über die Befehlszeile) zu deaktivieren und sie anschließend wieder zu aktivieren? Ich verwende PostgreSQL 9.1.

21

Sie suchen also nach anderen Tabellen in einer CHECK -Einschränkung .

CHECK Einschränkungen sollen IMMUTABLE Prüfungen ausführen. Was für eine Zeile gleichzeitig in Ordnung ist, sollte in any Zeit in Ordnung sein. So werden CHECK Einschränkungen im SQL-Standard definiert. Das ist auch der Grund für diese Einschränkung ( laut Dokumentation ):

Derzeit dürfen CHECK -Ausdrücke keine Unterabfragen enthalten und nicht auf andere Variablen als Spalten der aktuellen Zeile verweisen.

Ausdrücke in CHECK -Einschränkungen dürfen jetzt Funktionen verwenden, auch benutzerdefinierte Funktionen. Diese sollten auf IMMUTABLE -Funktionen beschränkt sein, aber Postgres erzwingt dies derzeit nicht. Demnach verwandte Diskussion über pgsql-Hacker besteht ein Grund darin, Verweise auf die aktuelle Zeit zuzulassen, die von Natur aus nicht IMMUTABLE ist.

Sie suchen jedoch nach Zeilen einer anderen Tabelle, was völlig gegen die Funktionsweise von CHECK -Einschränkungen verstößt. Ich bin nicht überrascht, dass pg_dump Dies nicht vorsieht.

Verschieben Sie Ihren Scheck in einer anderen Tabelle in einen Trigger (das ist das richtige Werkzeug), und er sollte mit modernen Versionen von Postgres funktionieren.

PostgreSQL 9.2 oder höher

Während das oben Gesagte für jede Version von Postgres gilt, wurden mit Postgres 9.2 verschiedene Tools eingeführt, um Ihnen in Ihrer Situation zu helfen:

pg_dump Option --exclude-table-data

Eine einfache Lösung wäre, die Datenbank ohne Daten für die verletzende Tabelle zu entleeren mit:

--exclude-table-data=my_schema.my_tbl

Fügen Sie dann am Ende des Dumps nur die Daten für diese Tabelle hinzu mit:

--data-only --table=my_schema.my_tbl

Es können jedoch Komplikationen mit anderen Einschränkungen für dieselbe Tabelle auftreten. Es gibt eine noch bessere Lösung :

NOT VALID

Es gibt den Modifikator NOT VALID Für Einschränkungen. Nur für FK-Einschränkungen in Version 9.1 verfügbar, diese wurden jedoch in 9.2 auf CHECK Einschränkungen erweitert. Pro Dokumentation :

Wenn die Einschränkung mit NOT VALID Markiert ist, wird die möglicherweise langwierige Erstprüfung, um sicherzustellen, dass alle Zeilen in der Tabelle die Einschränkung erfüllen, übersprungen. Die Einschränkung wird weiterhin für nachfolgende Einfügungen oder Aktualisierungen [...] erzwungen.

Eine einfache Postgres-Dump-Datei besteht aus drei "Abschnitten":

  • pre_data
  • data
  • post-data

In Postgres 9.2 wurde auch die Option eingeführt, Abschnitte separat mit -- section=sectionname Zu sichern, was jedoch bei dem vorliegenden Problem nicht hilft.

Hier wird es interessant. Pro Dokumentation :

Post-Data-Elemente enthalten Definitionen von Indizes, Triggern, Regeln und Einschränkungen, die keine validierten Prüfbedingungen sind . Vordatenelemente umfassen alle anderen Datendefinitionselemente.

Meine kühne Betonung.
Sie können die fehlerhafte Einschränkung CHECK in NOT VALID Ändern, wodurch die Einschränkung in den Abschnitt post-data Verschoben wird. Löschen und neu erstellen:

ALTER TABLE a DROP CONSTRAINT a_constr_1;
ALTER TABLE a ADD  CONSTRAINT a_constr_1 CHECK (fail_if_b_empty()) NOT VALID;

Dies sollte Ihr Problem lösen. Sie können die Einschränkung sogar in diesem Zustand belassen , da dies besser widerspiegelt, was sie tatsächlich tut: neue Zeilen prüfen, aber keine Garantie dafür geben vorhandene Daten. An einer NOT VALID - Prüfbedingung ist nichts auszusetzen. Wenn Sie es vorziehen, können Sie es später validieren:

ALTER TABLE a VALIDATE CONSTRAINT a_constr_1;

Aber dann sind Sie wieder im Status Quo Ante.

19

Es scheint, dass dies auf die Art und Weise zurückzuführen ist, wie pg_dump Den Speicherauszug erstellt. Beim Betrachten des tatsächlichen Speicherauszugs stellte ich fest, dass die Einschränkung CHECK in der Speicherauszugsdatei vorhanden war. Dabei wurde die Syntax verwendet, die Teil des Befehls CREATE TABLE Ist:

CREATE TABLE a (
    i integer NOT NULL,
    CONSTRAINT a_constr_1 CHECK (fail_if_b_empty())
);      

Dies führt bei der Wiederherstellung der Datenbank zu einem Fehler, da die Prüfung durchgeführt wird, bevor entweder die Tabelle a oder die Tabelle b Daten enthält. Wenn jedoch die Dump-Datei bearbeitet wird und das CHECK stattdessen mit der folgenden Syntax am Ende der Dump-Datei hinzugefügt wird:

ALTER TABLE a ADD CONSTRAINT a_constr_1 CHECK (fail_if_b_empty()); 

... dann gibt es kein Problem bei der Restaurierung.

Mit einem TRIGGER kann genau dieselbe Logik implementiert werden wie im folgenden Skript:

CREATE OR REPLACE FUNCTION fail_if_b_empty (
    ) RETURNS BOOLEAN AS $$
    SELECT EXISTS (SELECT 1 FROM b)
$$ LANGUAGE SQL;

DROP TABLE IF EXISTS a;

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);

CREATE TRIGGER tr1 AFTER INSERT OR UPDATE ON a
FOR EACH ROW
EXECUTE PROCEDURE fail_if_b_empty();  

In diesem Fall erstellt pg_dump (Standardmäßig) den Trigger am Ende der Dump-Datei (und nicht in der Anweisung CREATE TABLE Wie bei einer Prüfung), sodass die Wiederherstellung erfolgreich ist .