web-dev-qa-db-ja.com

PostgreSQL-制約の無効化

別のテーブルの主キーを参照するfk制約を持つ約500万行のテーブル(約500万行)があります。

両方のテーブルから約75000行を削除する必要があります。 fk制約を有効にしてこれを実行しようとすると、許容できない時間がかかることを知っています。

Oracleのバックグラウンドから来て、最初に考えたのは、制約を無効にし、削除を実行してから、再び制約を有効にすることでした。私がスーパーユーザーの場合、PostGresは制約トリガーを無効にできるようです(私はそうではありませんが、オブジェクトを所有/作成したユーザーとしてログインしています)が、それは私が望むものとは思えない。

もう1つのオプションは、制約を削除してから復元することです。テーブルのサイズを考えると、制約の再構築には時間がかかるのではないかと心配しています。

何かご意見は?

編集:ビリーの奨励の後、私は制約を変更せずに削除を試みましたが、10分以上かかります。ただし、削除しようとしているテーブルに自己参照外部キーが...重複している(およびインデックスが付けられていない)ことを発見しました。

最終更新-自己参照外部キーを削除し、削除して追加し直しました。ビリーは正解ですが、残念ながら彼のコメントを回答として受け入れることはできません。

42
azp74

以前のコメントによると、それは問題になるはずです。それは、あなたが探しているものかもしれないコマンドがあります-それはすべての削除ではなくCOMMITでチェックされるように制約を遅延に設定します。すべての行の大きなDELETEを1つだけ実行している場合、違いはありませんが、分割して実行している場合は違います。

SET CONSTRAINTS ALL DEFERRED

その場合にあなたが探しているものです。制約は、遅延させる前にDEFERRABLEとしてマークする必要があることに注意してください。例えば:

ALTER TABLE table_name
  ADD CONSTRAINT constraint_uk UNIQUE(column_1, column_2)
  DEFERRABLE INITIALLY IMMEDIATE;

制約は、次のようにトランザクションまたは関数で延期できます。

CREATE OR REPLACE FUNCTION f() RETURNS void AS
$BODY$
BEGIN
  SET CONSTRAINTS ALL DEFERRED;

  -- Code that temporarily violates the constraint...
  -- UPDATE table_name ...
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
49
Magnus Hagander

私のために働いたのは、TRIGGERS操作に関与するテーブルのDELETEを1つずつ無効にすることでした。

ALTER TABLE reference DISABLE TRIGGER ALL;
DELETE FROM reference WHERE refered_id > 1;
ALTER TABLE reference ENABLE TRIGGER ALL;

ソリューションはバージョン9.3.16で機能しています。私の場合、DELETE操作の実行時間は45分から14秒になりました。

@amphetamachineのコメントセクションに記載されているように、このタスクを実行するには、テーブルに対するadmin権限が必要です。

14
gersonZaragocin

DISABLE TRIGGER ALLを試してpermission denied: "RI_ConstraintTrigger_a_16428" is a system triggerのようなエラーが表示された場合(Amazon RDSでこれを取得しました)、これを試してください:

set session_replication_role to replica;

これが成功すると、テーブル制約の基礎となるすべてのトリガーが無効になります。変更がDBを一貫した状態のままにすることを確認するのはあなた次第です!

次に、完了したら、セッションのトリガーと制約を再度有効にします:

set session_replication_role to default;
5
Jonathan Fuerth

(この答えは、選択範囲だけでなく、これらのテーブルのすべての行を削除することが意図されていることを前提としています。)

私もこれをしなければなりませんでしたが、テストスイートの一部として。 SOの他の場所 を提案した答えを見つけました。次のように TRUNCATE TABLE を使用します。

TRUNCATE TABLE <list-of-table-names> [RESTART IDENTITY] [CASCADE];

次は、テーブルからすべての行をすばやく削除しますtable1table2、およびtable3(リストされていないテーブルからこれらのテーブルの行への参照がない場合):

TRUNCATE TABLE table1, table2, table3;

リストされたテーブル間で参照がある限り、PostgreSQLは参照整合性を気にせずにすべての行を削除します。リストされているもの以外のテーブルがこれらのテーブルのいずれかの行を参照している場合、クエリは失敗します。

ただし、クエリを修飾して、リストされたテーブルへの参照ですべてのテーブルを切り捨てることもできます(これは試していませんが)。

TRUNCATE TABLE table1, table2, table3 CASCADE;

デフォルトでは、これらのテーブルのシーケンスは番号付けを再開しません。新しい行は、シーケンスの次の番号から継続します。シーケンス番号付けを再開するには:

TRUNCATE TABLE table1, table2, table3 RESTART IDENTITY;
4
Joe Lapp

私のPostgreSQLは9.6.8です。

set session_replication_role to replica;

私のために働いていますが、許可が必要です。

スーパーユーザーでpsqlにログインします。

Sudo -u postgres psql

次に、データベースに接続します

\c myDB

そして実行:

set session_replication_role to replica;

これで、制約付きのテーブルから削除できます。

2
Weekend Baf