私はPostgreSQLデータベースのダンプを取得しました:
pg_dump -U user-name -d db-name -f dumpfile
次に、次のコマンドを使用して別のデータベースに復元します。
psql X -U postgres -d db-name-b -f dumpfile
私の問題は、データベースに参照制約、チェック、およびトリガーが含まれており、これらのチェック(特にチェックのように思われる)の一部が復元中に失敗することです。たとえば、テーブルに行を挿入することは、CHECK
関数を呼び出すplpgsql
に関連付けることができます。この関数は、他の無関係なテーブルで条件が保持されているかどうかをチェックします。後者のテーブルが前のpsql
によってロードされない場合、エラーが発生します。
以下は、pg_dump
を使用して一度ダンプされたデータベースを復元できないデータベースを生成するSSCCEです。
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());
ダンプの復元中にこのようなすべての制約を(コマンドラインから)無効にして、後で再び有効にする方法はありますか? PostgreSQL 9.1を実行しています。
したがって、他のテーブルをCHECK
制約で検索します。
CHECK
制約はIMMUTABLE
チェックを実行することになっています。行に対して一度にOKを渡すものは、いつでも時刻にOKを渡す必要があります。これが、SQL標準でのCHECK
制約の定義方法です。これもこの制限の理由です( ドキュメントごと ):
現在、
CHECK
式にはサブクエリを含めることも、現在の行の列以外の変数を参照することもできません。
現在、CHECK
制約内の式は、ユーザー定義関数であっても、関数を使用できます。それらはIMMUTABLE
関数に制限されるべきですが、Postgresは現在これを強制しません。これ pgsql-hackersに関する関連ディスカッション によると、1つの理由は、本来はIMMUTABLE
ではない現在時刻への参照を許可することです。
しかし、あなたは別のテーブルの行を調べていますが、これはCHECK
制約の機能に完全に違反しています。 pg_dump
がこれに対応していないことに驚いていません。
別のテーブルのチェックをtrigger(適切なツールです)に移動すると、Postgresの最新バージョンで動作するはずです。
上記はPostgresのすべてのバージョンに当てはまりますが、Postgres 9.2では状況に役立ついくつかのツールが導入されています。
--exclude-table-data
簡単な解決策は、違反しているテーブルのデータなしでデータベースをダンプすることです:
--exclude-table-data=my_schema.my_tbl
次に、ダンプの最後にこのテーブルのデータのみを追加します。
--data-only --table=my_schema.my_tbl
ただし、同じテーブルに対する他の制約が複雑になる可能性があります。偶数がありますより良い解決策:
NOT VALID
制約にはNOT VALID
修飾子があります。 v9.1のFK制約でのみ使用できますが、9.2でCHECK
制約に拡張されました。 ドキュメントごと:
制約に
NOT VALID
のマークが付いている場合、テーブル内のすべての行が制約を満たすことを確認するために時間がかかる可能性のある初期チェックがスキップされます。制約は引き続き後続の挿入または更新に対して適用されます[...]
プレーンなpostgresダンプファイルは、3つの「セクション」で構成されています。
pre_data
data
post-data
Postgres 9.2は-- section=sectionname
を使用してセクションを個別にダンプするオプションも導入しましたが、それは当面の問題の解決にはなりません。
ここが面白いところです。 ドキュメントごと:
データ後の項目には、インデックス、トリガー、ルール、および検証されたチェック制約以外の制約の定義が含まれます。事前データ項目には、他のすべてのデータ定義項目が含まれます。
大胆な強調鉱山。
問題のあるCHECK
制約をNOT VALID
に変更すると、制約がpost-data
セクションに移動します。ドロップして再作成:
ALTER TABLE a DROP CONSTRAINT a_constr_1;
ALTER TABLE a ADD CONSTRAINT a_constr_1 CHECK (fail_if_b_empty()) NOT VALID;
これで問題が解決するはずです。 制約をその状態のままにするのほうが実際の動作を反映しているため、新しい行をチェックしますが、既存のデータは保証しません。NOT VALID
チェック制約に問題はありません。必要に応じて、後で検証できます。
ALTER TABLE a VALIDATE CONSTRAINT a_constr_1;
しかし、その後、あなたは現状維持に戻ります。
これは、pg_dump
がダンプを作成する方法が原因であると思われます。実際のダンプを見ると、CREATE TABLE
コマンドの一部である構文を使用して、CHECK
制約がダンプファイルに存在することがわかりました。
CREATE TABLE a (
i integer NOT NULL,
CONSTRAINT a_constr_1 CHECK (fail_if_b_empty())
);
これにより、テーブルa
またはテーブルb
にデータが入る前にチェックが行われるため、データベースの復元時にエラーが発生します。ただし、ダンプファイルが編集され、代わりに次の構文を使用してCHECK
がダンプファイルの最後に追加された場合:
ALTER TABLE a ADD CONSTRAINT a_constr_1 CHECK (fail_if_b_empty());
...その後、復元に問題はありません。
まったく同じロジックは、次のスクリプトのようにTRIGGER
を使用して実装できます。
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();
ただし、この場合、pg_dump
は(デフォルトでは)ダンプファイルの最後に(チェックの場合のようにCREATE TABLE
ステートメントではなく)トリガーを作成するため、復元は成功します。