postgresから行を一括削除する最も効率的な方法


23

私はPostgreSQLから大量の行を削除する最も効率的な方法は何だろうと思っています。このプロセスは、テーブルにデータ(挿入と削除のデルタ)を一括インポートするための毎日の定期的なタスクの一部になります。削除する行は数千、場合によっては数百万になる可能性があります。

1行に1つの主キーのファイルがあります。私が考えていた2つの選択肢は以下のようなものでしたが、PostgreSQLの内部について十分な知識がなく、十分な情報を得た上で最善の判断を下すことができません。

  • 主キーを使用DELETEして、ファイル内の各行に対してクエリを実行しますWHERE(またはnIN()句を使用してバッチで削除をグループ化します)。
  • COPYコマンドを使用して主キーを一時テーブルにインポートし、結合を使用してメインテーブルから削除する

どんな提案でも大歓迎です!


1
同じ質問はここでは詳細に回答されていますstackoverflow.com/a/8290958
サイモン・

回答:


25

2番目のオプションははるかにクリーンであり、十分なパフォーマンスを発揮して価値があります。別の方法として、巨大なクエリを作成します。これは計画と実行が非常に面倒です。一般的に、ここでPostgreSQLに作業を任せる方が良いでしょう。一般に、適切に実行するために説明している方法で数万行の更新を見つけましたが、実行しないようにする1つの重要なことがあります。

その方法は、削除で選択と結合を使用することです。

DELETE FROM foo WHERE id IN (select id from rows_to_delete);

どんな状況でも、大きなテーブルで次のようにすべきではありません。

DELETE FROM foo WHERE id NOT IN (select id from rows_to_keep);

これは通常、ネストされたループの反結合を引き起こし、パフォーマンスがかなり問題になります。そのルートに行かなければならない場合、代わりにこれをしてください:

DELETE FROM foo 
WHERE id IN (select id from foo f 
          LEFT JOIN rows_to_keep d on f.id = d.id
              WHERE d.id IS NULL);

PostgreSQLは通常、悪い計画を回避するのに非常に優れていますが、良い計画と悪い計画の間に大きな違いをもたらす可能性のある外部結合を含む場合がまだあります。

これはもう少し遠くにさまよいますが、INからNOT INに移動してクエリパフォーマンスタンクを見るのがどれほど簡単かという点に言及する価値があります。


とても助かりました、ありがとう!ただし、この特定のケースでは、「クエリの組み合わせ」を使用する方が効率的であることがわかりました。例えば IN ( select id from foo except select id from rows_to_keep ) 参照くださいpostgresql.org/docs/9.4/static/queries-union.html
のUFO

1

同様の問題を抱えていたので、この質問に出会いました。3億行以上のデータベースをクリーンアップしています。最終的なデータベースには、元のデータの約30%しかありません。同様のシナリオに直面している場合、実際には削除するよりも新しいテーブルに挿入してインデックスを再作成する方が簡単です。

のような何かをする

CREATE temp_foo as SELECT * FROM foo WHERE 1=2;
INSERT INTO temp_foo (SELECT * FROM foo where foo.id IN (SELECT bar.id FROM BAR);

fooとbarに適切なインデックスを付けると、Seqスキャンを回避できます。

次に、テーブルのインデックスを再作成して名前を変更する必要があります。

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