更新数据库行,而不在PostgreSQL的9.2锁定表(Updating database rows

2019-08-19 02:36发布

试图在一个表上运行一个像这样的更新语句,使用PostgreSQL 9.2:

UPDATE table
    SET a_col = array[col];

我们需要能够在10M〜行表运行它,而不是把它锁住表(因而更新运行时正常操作仍可发生)。 我相信使用游标可能会是正确的解决方案,但我真的不知道,如果是,或者我应该如何使用游标实现它。

我想出了这个光标代码,我想可能是很好的。

编辑:增加光标功能

CREATE OR REPLACE FUNCTION update_fields() RETURNS VOID AS $$
DECLARE
        cursor CURSOR FOR SELECT * FROM table ORDER BY id FOR UPDATE;
BEGIN
        FOR row IN cursor LOOP
                UPDATE table SET
                        a_col = array[col],
                        a_col2= array[col2]
                WHERE CURRENT OF cursor;
        END LOOP;
END;
$$ LANGUAGE plpgsql;

Answer 1:

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的更多信息,松散相关答案:

  • 掉落或从PostgreSQL的存储过程创建数据库

您使用游标的方法

在函数内部光标不会买任何东西 。 任何功能自动封闭在一个事务,所有的锁只在事务结束时释放。 即使你使用CLOSE cursor (你没有)也只是释放一些资源,但上不了台面释放获取的锁。 我引述手册:

CLOSE关闭门户底层一个打开的游标。 这可以用来提前释放资源,在事务结束,或者释放被再次打开游标变量。

您需要运行单独的事务或(AB)使用DBLINK这确实是给你的。



文章来源: Updating database rows without locking the table in PostgreSQL 9.2