MVCC
首先,如果“正常操作”包含SELECT
查询,MVCC 模型会自动处理它。UPDATE
不会阻塞SELECT
,反之亦然。SELECT
只看到已提交的数据(或在同一事务中已完成的内容),因此在UPDATE
完成(已提交)之前,其他事务的结果对其他事务不可见。
性能/膨胀
如果您没有其他对象引用该表,
并且您没有并发写操作(这会丢失!),
并且您可以在表上提供一个非常短的排他锁,
并且您有额外的磁盘空间,当然:
您可以通过在后台创建表的更新版本来将锁定保持在最低限度。确保它具有作为替代品的所有内容,然后删除原件并重命名副本。
CREATE TABLE tbl_new (LIKE tbl_org INCLUDING CONSTRAINTS);
INSERT INTO tbl_new
SELECT col_a, col_b, array[col] aS col_c
FROM tbl_org;
我正在使用CREATE TABLE (LIKE .. INCLUDING CONSTRAINTS)
,因为(在此处引用手册):
非空约束总是被复制到新表中。CHECK
仅当指定时才会复制约束INCLUDING CONSTRAINTS
;永远不会复制其他类型的约束。
确保新表已准备就绪。然后:
DROP tbl_org;
ALTER TABLE tbl_new RENAME TO tbl_org;
导致非常短的时间窗口,其中表被独占锁定。
这实际上仅与性能有关。它会很快创建一个没有任何膨胀的新表。如果你有外键或视图,你仍然可以走这条路,但你必须准备一个脚本来删除和重新创建这些对象,这可能会创建额外的独占锁。
并发写入
使用并发写入操作,您实际上所能做的就是将您的更新分成几块。您不能在单个事务中执行此操作,因为锁定仅在事务结束时释放。
您可以使用dblink,它可以在另一个数据库(包括它自己)上启动独立事务。这样,您可以在单个DO
语句或带有循环的 plpgsql 函数中完成所有操作。这是一个松散相关的答案,其中包含有关 dblink 的更多信息:
您使用光标的方法
函数内的光标不会给您带来任何好处。任何功能都自动包含在事务中,所有锁仅在事务结束时释放。即使您使用CLOSE cursor
(您不使用)它也只会释放一些资源,但不会释放表上获得的锁。我引用手册:
CLOSE
关闭打开光标下的门户。这可用于在事务结束之前释放资源,或释放游标变量以再次打开。
您需要运行单独的事务或(ab)使用为您执行此操作的dblink。