更新数据库行而不在PostgreSQL 9.2中锁定表

时间:2013-04-02 17:45:55

标签: database postgresql cursor sql-update

尝试使用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;

1 个答案:

答案 0 :(得分:15)

MVCC

首先,如果“正常操作”包含SELECT个查询,MVCC model会自动处理。 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),因为(quoting the manual here):

  

始终将非空约束复制到新表中。 CHECK   只有在指定INCLUDING CONSTRAINTS时才会复制约束;   其他类型的约束永远不会被复制。

确保新表已准备就绪。然后:

DROP tbl_org;
ALTER TABLE tbl_new RENAME TO tbl_org;

在非常短的时间窗口中生成表格,其中表格是专门锁定的。

这实际上只是关于性能。它创建了一个没有任何臃肿的新表。如果您有外键或视图,您仍然可以使用该路径,但您必须准备一个脚本来删除并重新创建这些对象,这可能会创建额外的独占锁。

并发写

使用并发写入操作,您可以做的就是将更新分成块。您不能在单个事务中执行此操作,因为锁仅在事务结束时释放。

可以使用dblink,它可以在另一个数据库上启动独立的事务,包括它自己。这样,您可以在单个DO语句或带循环的plpgsql函数中完成所有操作。这是一个松散相关的答案,有关dblink的更多信息:

您使用游标的方法

该功能内的光标不会给你带来任何东西。任何函数都自动包含在事务中,并且所有锁仅在事务结束时释放。 即使您使用CLOSE cursor(您没有使用),它也只会释放一些资源,但会释放获取的锁定。我引用手册:

  

CLOSE关闭打开游标底层的门户。这可以用来   在交易结束之前释放资源,或者释放资源   光标变量再次打开。

您需要运行 单独的交易或(ab)使用dblink来为您执行此操作。