试图在一个表上运行一个像这样的更新语句,使用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;
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这确实是给你的。