Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Database 在PostgreSQL 9.2中更新数据库行而不锁定表_Database_Postgresql_Cursor_Sql Update - Fatal编程技术网

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

Database 在PostgreSQL 9.2中更新数据库行而不锁定表,database,postgresql,cursor,sql-update,Database,Postgresql,Cursor,Sql Update,尝试使用PostgreSQL 9.2在表上运行类似的update语句: UPDATE table SET a_col = array[col]; 我们需要能够在~10M行的表上运行此操作,并且不让它锁定表(因此在更新运行时仍然可以执行正常操作)。我相信使用游标可能是正确的解决方案,但我真的不知道它是否正确,也不知道应该如何使用游标来实现它 我已经想出了这个光标代码,我认为这可能是好的 编辑:添加光标功能 CREATE OR REPLACE FUNCTION update_fields(

尝试使用PostgreSQL 9.2在表上运行类似的update语句:

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; 创建或替换函数update_fields()返回VOID作为$$ 声明 光标用于按id从表顺序中选择*进行更新; 开始 对于游标循环中的行 更新表集 a_col=数组[col], a_col2=数组[col2] 其中光标的当前位置; 端环; 结束; $$语言plpgsql; MVCC 首先,如果“正常操作”包括
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;
我正在使用
创建表(比如..包括约束)
,因为():

NOTNULL约束总是复制到新表中<代码>检查 仅当指定了包含约束的
时,才会复制约束;
其他类型的约束将永远不会被复制

确保新桌子准备好了。然后:

DROP tbl_org;
ALTER TABLE tbl_new RENAME TO tbl_org;
结果在很短的时间窗口内,表被独占锁定

这实际上只是关于性能。它可以相当快地创建一个没有任何膨胀的新表。如果您有外键或视图,您仍然可以这样做,但是您必须准备一个脚本来删除并重新创建这些对象,这可能会创建额外的独占锁

并发写入 对于并发写操作,实际上您所能做的就是将更新分块。您不能在单个事务中这样做,因为锁只在事务结束时释放

您可以使用,它可以在另一个数据库(包括自身)上启动独立事务。通过这种方式,您可以在一个
do
语句或带有循环的plpgsql函数中完成所有操作。下面是一个松散相关的答案,其中包含有关dblink的更多信息:

使用游标的方法 函数中的光标不会为您购买任何东西。任何函数都自动包含在事务中,所有锁仅在事务结束时释放。 即使您使用了(您不使用),它也只会释放一些资源,而不会释放表上获取的锁。我引述该手册:

CLOSE
关闭打开光标下的门户。这可以用来 在事务结束之前释放资源,或释放 要再次打开的游标变量


您需要运行单独的事务或(ab)使用哪个选项来运行该事务。

是否有其他对象引用该表,如视图的外键?@ErwinBrandstetter没有,根本没有外键。非常感谢您的回答。“正常操作”还包括update语句。我想用光标(请看我更新的问题)来做这件事,但我不确定这是否是个好主意。@Juancarlosto:恐怕,光标不是个好主意。我在回答中加了一点。