使用光标在Postgres中批量删除

时间:2018-10-23 13:33:05

标签: postgresql cursor sql-delete

我是Postgres的新手,并且有一个任务要从未分区创建的活动表中删除记录。现在我的头是要创建一个游标以受控方式删除记录。

我头脑中的步骤

  • 声明一个游标,将其打开
  • 将记录提取到游标中,日期上将有一个过滤器
  • 传递受控记录说5000次/交易以删除语句
  • 循环执行,直到完成初始提取
  • 退出循环并关闭光标

这有意义吗?

1 个答案:

答案 0 :(得分:0)

DELETE。忘记光标。

除非表很大并且您要删除很大比例的行,否则分批处理是没有意义的。即使到那时,也几乎没有任何意义。我能想到的唯一原因是允许VACUUM尽早删除死元组,这在特​​殊情况下可能会有所帮助。还是为了逃避锁定争用(可能的死锁?),但这引出了一个问题,即为什么要删除的行首先应该由并发事务锁定。

为此锁每行。与并发的INSERTUPDATE不同行没有冲突。 (如果您有针对某些相同行的UPDATE,则会遇到更大的问题。)无论如何,在Postgres上都是writers don't block readers

可以创建一个SQL cursor with the WITH HOLD option,然后在单独的事务中将其与DELETE ... WHERE CURRENT OF一起使用。但是您必须抛出FOR UPDATE,无论如何都锁定所有受影响的行。几乎没有道理,除非您想快速锁定所有受影响的行,但在删除之前仍要对它们进行某些操作,并且可能会有更聪明的方法...

有意义的是,将大UPDATE分区(在单独的事务中),以便死掉的元组可以在H.O.T.中重用。更新(手动VACUUM或自动真空启动后)。但这几乎不适用于不重用空间的DELETE操作。另外,DELETEUPDATE快得多。

在不太可能发生的情况中,您仍然需要分批执行操作,但仍不要使用光标。使用类似的东西:

WITH cte AS (
   SELECT id                 -- your PK
   FROM   tbl
   WHERE  date < $something  -- your condition
   LIMIT  50000
   FOR    UPDATE             -- SKIP LOCKED ?
   )
DELETE FROM tbl
USING  cte
WHERE  tbl.id = cte.id;

重复直到找不到行。

请参阅: