在PL/PGSQL中循环通过游标而不锁定表
我有一个简单的PL/PGSQL块Postgres 9.5,它循环表中的记录并有条件地更新一些记录 下面是一个简化的示例: 做$$ 声明 -定义一个游标来循环记录 我的\u cool\u光标用于 选择 u、 id作为用户\u id, u、 名称作为用户名, u、 以用户身份发送电子邮件 来自用户u ; 开始 在my_cool_光标循环中记录 -简化示例: -如果用户的名字是“Anjali”,请将电子邮件设置为空 如果record.user_name='Anjali',则 开始 更新用户设置email=NULL,其中id=record.user\u id; 终止 如果结束; 端环; 终止 $$语言plpgsql; 我想通过我的应用程序,通过控制台等,直接对我的数据库执行此块。。。。我不想创建函数或存储过程来执行此操作 问题 问题是游标和循环在我的users表上创建了一个表级锁,因为外部BEGIN…END之间的所有内容都在事务中运行。这将阻止针对它的任何其他未决查询。如果用户足够大,则会将其锁定几秒钟甚至几分钟 我试过的 我尝试在每次更新后提交,以便它定期清除事务和锁。我惊讶地看到以下错误消息:在PL/PGSQL中循环通过游标而不锁定表,sql,postgresql,transactions,plpgsql,postgresql-9.5,Sql,Postgresql,Transactions,Plpgsql,Postgresql 9.5,我有一个简单的PL/PGSQL块Postgres 9.5,它循环表中的记录并有条件地更新一些记录 下面是一个简化的示例: 做$$ 声明 -定义一个游标来循环记录 我的\u cool\u光标用于 选择 u、 id作为用户\u id, u、 名称作为用户名, u、 以用户身份发送电子邮件 来自用户u ; 开始 在my_cool_光标循环中记录 -简化示例: -如果用户的名字是“Anjali”,请将电子邮件设置为空 如果record.user_name='Anjali',则 开始 更新用户设置emai
ERROR: cannot begin/end transactions in PL/pgSQL
HINT: Use a BEGIN block with an EXCEPTION clause instead.
我不太清楚这是怎么做到的。是不是要求我提出一个例外来强制提交?我试着阅读,但它只提到回滚,所以我看不到任何提交的方法
如何在上面的循环中定期提交事务?
更一般地说,我的方法是正确的吗?有没有更好的方法在不锁定表的情况下循环记录?
1.
您不能在PostgreSQL或命令中提交所有plpgsql或任何其他PL。您报告的错误消息与Postgres 9.5有关:
A可以在11级或更高级别的研究生中做到这一点。见:
在旧版本中实现自治事务的变通方法有限:
但在本案例中,您不需要任何这些
2.
改用简单的更新:
仅锁定实际更新了角点大小写异常的行。由于这比光标在整个表上移动快得多,所以锁也非常简短
添加的和电子邮件与NULL不同,避免了空更新。相关的:
在plpgsql函数中,显式游标很少有用。如果要避免长时间锁定行,还可以使用HOLD定义游标,例如使用SQL语句 这样的游标可以跨事务边界使用,因此您可以在一定数量的更新之后提交。您付出的代价是必须在数据库服务器上具体化游标
由于不能在函数中使用事务语句,因此必须在应用程序代码中使用过程或提交。光标不会阻止其他只读查询。但是我不认为有必要用一个缓慢而低效的光标来开始感谢。我给出的UPDATE语句只是一个简化的示例。我真正的逻辑要复杂得多,所以我不认为我可以在一次更新中解决这个问题。@user2490003:你仍然可以。也许值得再问一个关于细节的问题。。。
ERROR: cannot begin/end transactions in PL/pgSQL
UPDATE users
SET email = NULL
WHERE user_name = 'Anjali'
AND email IS DISTINCT FROM NULL; -- optional improvement