从 postgres 批量删除行的最有效方法

tar*_*eld 32 postgresql delete bulk

我想知道从 PostgreSQL 中删除大量行的最有效方法是什么,这个过程将是每天重复性任务的一部分,以将数据(插入 + 删除的增量)批量导入表中。可能有数千甚至数百万行要删除。

我有一个主键文件,每行一个。我想到的两个选项与下面的内容一致,但我对 PostgreSQL 的内部结构知之甚少,无法做出最好的明智决定。

  • DELETE使用简单WHERE的主键对文件中的每一行执行查询(或n使用IN()子句分批删除)
  • 使用COPY命令将主键导入到临时表中,然后使用连接从主表中删除

任何建议将不胜感激!

Chr*_*ers 31

您的第二个选择要干净得多,并且性能足够好,值得。您的替代方案是构建巨大的查询,这将非常痛苦地计划和执行。一般来说,让 PostgreSQL 在这里完成工作会更好。一般而言,我发现以您所描述的方式对数万行进行更新以充分执行,但有一件重要的事情要避免。

这样做的方法是在删除中使用选择和连接。

DELETE FROM foo WHERE id IN (select id from rows_to_delete);
Run Code Online (Sandbox Code Playgroud)

在任何情况下,您都不应使用大表进行以下操作:

DELETE FROM foo WHERE id NOT IN (select id from rows_to_keep);
Run Code Online (Sandbox Code Playgroud)

这通常会导致嵌套循环反连接,这将使性能相当有问题。如果您最终不得不走那条路,请改为执行以下操作:

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);
Run Code Online (Sandbox Code Playgroud)

PostgreSQL 通常非常擅长避免糟糕的计划,但仍然存在涉及外连接的情况,这会在好计划和坏计划之间产生很大差异。

这是在更远的地方徘徊,但我认为值得一提,因为从 IN 转到 NOT IN 并观察查询性能罐是多么容易。


小智 6

我遇到这个问题是因为我遇到了类似的问题。我正在清理一个拥有 300M+ 行的数据库,最终的数据库将只有原始数据的 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);
Run Code Online (Sandbox Code Playgroud)

通过对 foo 和 bar 进行适当的索引,您可以避免 Seq 扫描。

然后您必须重新索引并重命名该表。