我是 Postgres 新手,有一项任务是从未分区创建的活动表中删除记录。现在我的想法是创建一个游标来以受控的方式删除记录。
我脑子里的步骤:
这有意义吗?
只是
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
可以使用指数,前景会更好。
参见: