PostgreSQLで非常に遅いDELETE、回避策?


30

PostgreSQL 9.2には、約70個のテーブルを持つメインスキーマと、それぞれ30個のテーブルからなる可変構造のクライアントごとのスキーマを持つデータベースがあります。クライアントスキーマには、メインスキーマを参照する外部キーがあり、その逆はありません。

以前のバージョンから取得した実際のデータをデータベースに入力し始めたところです。メインスキーマの非常に中央のテーブルで一括削除を行う必要があったときに、DBは約1.5 GBに達しました(数週間で数十GBに達すると予想されています)。関係するすべての外部キーは、DELETE CASCADEでマークされます。

これに長い時間がかかることは驚きではありませんでしたが、12時間後には、最初からやり直してDBを削除し、移行を再開する方が良いことが明らかになりました。しかし、後でDBが稼働し、さらに大きくなったときにこの操作を繰り返す必要がある場合はどうなりますか?より高速な代替方法はありますか?

中央テーブルから最も遠いテーブルから開始し、テーブルごとに依存する行を削除する依存テーブルを参照するスクリプトを書いたら、もっと速くなるでしょうか?

重要な詳細は、いくつかのテーブルにトリガーがあることです。


4
5年後、私は受け入れられた答えを変えています。遅いDELETEは、ほとんどの場合、削除されるテーブルを直接または間接的に参照する外部キーのインデックスが欠落していることが原因です。DELETEステートメントで起動するトリガーも速度を低下させる可能性がありますが、解決策はほとんど常に(たとえば、欠落しているインデックスを追加することにより)実行を高速化し、すべてのトリガーを無効にしないことです。
jd。

回答:


30

同様の問題がありました。ON DELETE CASCADE結局のところ、それらのカスケードされた削除は非常に遅いため、これらのトリガーは非常に遅くなりました。

参照元テーブルの外部キーフィールドにインデックスを作成することで問題を解決し、削除に数時間かかっていた時間を数秒に短縮しました。


うわー、これは私が数分で800万レコードを削除するのに役立ちました。しかし、私が理解していないのは、私のテーブルは他のテーブルへの参照のみを保持し、他のテーブルは私のテーブルへの参照を保持していないということです。それで、ここでの効果は正確に何ですか?(私は使用していませんON DELETE CASCADE
msrd0

2
これも私にとっては解決しました。これを試みる人EXPLAIN (ANALYZE, BUFFERS)は、1行の削除でクエリを実行でき、どの外部キー制約が最も長くかかったかを示すはずです(少なくとも私にとってはそうでした)。
ジャスティンワークマン

同じように、カスケード60万行で削除する必要があり、最初は操作ごとに2〜10の間でCPU使用率が100%でした。CPU使用率80%ですべてを削除するのに数分しかかかりませんでした。
-fillobotto

どこへの外部参照がある場合、ソース列には実際のインデックスが必要です。そうしないと、パフォーマンスが低下することに注意することが重要です。PRIMARYインデックスが十分であるかどうかUNIQUEはわかりませんが、インデックスはこの目的には間違いなく十分ではありません。
ミッコランタライネン

26

いくつかのオプションがあります。最良のオプションは、トリガーがヒットしないようにバッチ削除を実行することです。削除する前にトリガーを無効にしてから、再度有効にします。これにより、時間を大幅に節約できます。例えば:

ALTER TABLE tablename DISABLE TRIGGER ALL; 
DELETE ...; 
ALTER TABLE tablename ENABLE TRIGGER ALL;

ここでの主要なキーは、サブクエリの深さを最小限に抑えたいことです。この場合、関連する情報を格納する一時テーブルを設定して、削除時の深いサブクエリを回避できます。


私の場合、寝る前にDELETE FROMコマンドを開始しましたが、翌日にコンピューターに戻ったときにまだ実行されていませんでした。常に1つのコアで100%のCPU使用率。トリガーを無効にして再試行した後、20万件のレコードを削除するのに3秒かかりました。ありがとうございました!
ニックウッドハムズ

13

問題を解決する最も簡単な方法は、PostgreSQLから詳細なタイミングを照会することですEXPLAIN。そのためには、少なくとも1つのクエリを見つける必要があります。このクエリは完了しますが、予想よりも時間がかかります。この行が次のようになるとしましょう

delete from mydata where id='897b4dde-6a0d-4159-91e6-88e84519e6b6';

そのコマンドを実際に実行する代わりに、次のことができます

begin;
explain (analyze,buffers,timing) delete from mydata where id='897b4dde-6a0d-4159-91e6-88e84519e6b6';
rollback;

最終的にロールバックすると、データベースを実際に変更せずにこれを実行できますが、それでもどれだけの時間がかかったのかについての詳細なタイミングが得られます。それを実行した後、出力でいくつかのトリガーが大きな遅延を引き起こすことがわかります:

...
Trigger for constraint XYZ123: time=12311.292 calls=1
...

timeこのcontraintは12.3秒程度かかっチェックするように、ミリ秒(ミリ秒)です。INDEXこのトリガーを効果的に計算できるように、必要な列に新しい列を追加する必要があります。外部キー参照の場合、別のテーブルを参照する列(つまり、ターゲット列ではなくソース列)にインデックスを付ける必要があります。PostgreSQLはそのようなインデックスを自動的に作成せずDELETE、本当にそのインデックスが本当に必要な唯一の一般的なクエリです。その結果、DELETEインデックスが欠落しているために遅すぎるケースに突き当たるまで、長年のデータを蓄積している可能性があります。

その制約(または非常に長い時間がかかった他のこと)のパフォーマンスを修正したら、begin/ rollbackブロック内のコマンドを繰り返して、新しい実行時間を以前と比較できるようにします。1行の削除応答時間に満足するまで続行します(異なるインデックスを追加するだけで、25.6秒から15ミリ秒に1つのクエリを取得しました)。その後、ハッキングなしで完全な削除を完了することができます。

(注意してくださいEXPLAIN。正常に完了するクエリが必要です。一度、PostgreSQLが1つの削除が外部キー制約に違反することを理解するのに非常に時間がかかり、その場合EXPLAINは失敗のタイミングを出力しないため使用できません)という問題がありましたクエリ。このような場合にパフォーマンスの問題をデバッグする簡単な方法はわかりません。)


8

トリガーを無効にすると、DBの整合性が脅かされる可能性があるため、推奨できません。ただし、操作が制約失敗に耐えることが確かな場合は、次の方法でトリガーを無効にできます。SET session_replication_role = replica;

DELETEここを実行します。

トリガーを復元するには、次を実行します。 SET session_replication_role = DEFAULT;

ここのソース。


0

ON DELETE CASCADEトリガーを使用している場合、それらは何らかの理由で存在することが望ましいため、無効にしないでください。私のために働くもう1つのトリック(まだインデックスを追加する)は、カスケードの最後のテーブルから開始してメインテーブルに向かってデータを手動で削除する削除関数を作成することです。(これは、ON DELETE RESTRICTトリガーがあった場合に必要になるのと同じです)

CREATE TABLE tablea (
    tablea_uid integer
);

CREATE TABLE tableb (
    tableb_uid integer,
    tablea_rid integer REFERENCES tablea(tablea_uid)
);

CREATE TABLE tablec (
    tablec_uid integer,
    tableb_rid integer REFERENCES tableb(tableb_uid)
);

この場合、tablec、tableb、tableaのデータを削除します

CREATE OR REPLACE FUNCTION delete_in_order()
 RETURNS void AS $$

    DELETE FROM tablec;
    DELETE FROM tableb;
    DELETE FROM tablea;

$$ LANGUAGE SQL;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.