在Postgres中使用游标批量删除

问题描述 投票:0回答:1

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

我脑子里的步骤:

  • 声明一个游标,打开它
  • 将记录提取到游标中,其中将有日期过滤器
  • 通过控制记录比如5000/交易来删除语句
  • 循环直到初始获取完成
  • 退出循环并关闭光标

这有意义吗?

postgresql sql-delete database-cursor
1个回答
13
投票

只是

DELETE
。忘记光标。

除非您的表巨大并且您要删除很大比例的行,否则批量执行此操作是没有意义的。即便如此,也几乎没有任何意义。我能想到的唯一原因是允许

VACUUM
提前删除死元组,这在特殊情况下可能会有所帮助。或者避免锁定争用(可能的死锁?),但这引出了一个问题:为什么要删除的行首先应该由并发事务锁定。

锁是每行。并发

INSERT
UPDATE
不同 行不存在冲突。 (如果你有针对某些相同行的更新,那么你就会遇到更大的问题。)而且在 Postgres 上,作者不会阻止读者

可以使用WITH HOLD

选项
创建SQL游标,然后在单独的事务中将其与
DELETE ... WHERE CURRENT OF
一起使用。但你必须加入
FOR UPDATE
,无论如何都要锁定所有受影响的行。很少有意义,除非您想快速锁定所有受影响的行,但在删除之前仍对它们执行某些操作,并且可能有更聪明的方法...

在单独的事务中对大的

UPDATE
进行分区是有意义的,以便可以在 H.O.T 中重用死元组。更新(在手动
VACUUM
autovacuum
启动后)。但这几乎不适用于不重用空间的
DELETE
操作。而且,
DELETE
UPDATE
快很多。

万一您仍然需要批量执行此操作,仍然不要使用游标。使用类似的东西:

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

重复直到找不到行。

如果您的数据(大部分)以某种方式进行物理排序,则可以相应地对行进行排序(引用的

ORDER BY
)。
ORDER BY
会产生自己的成本,但每个
DELETE
可能能够访问更少的具有聚集行的数据页,并且速度更快。取决于用例;如果
ORDER BY
可以使用指数,前景会更好。

参见:

© www.soinside.com 2019 - 2024. All rights reserved.