我有一个需要对多个大表执行长时间更新的函数。在更新期间,一次需要在EXCLUSIVE模式下锁定2-3个表。
由于并非所有表都需要同时锁定,理想情况下我只想锁定那些我当时正在更新的表,然后在完成后删除锁。
例如
-- Lock first pair of tables
LOCK TABLE tbl1_a IN EXCLUSIVE MODE;
LOCK TABLE tbl1_b IN EXCLUSIVE MODE;
-- Perform the update on tbl1_a and tbl1_b
-- Release the locks on tbl1_a and tbl1_b
-- HOW???
-- Proceed to the next pair of tables
LOCK TABLE tbl2_a IN EXCLUSIVE MODE;
LOCK TABLE tbl2_b IN EXCLUSIVE MODE;
不幸的是,在plpgsql中没有等效的UNLOCK语句。删除LOCK的常规方法是COMMIT事务,但这在函数内部是不可能的。
这有什么解决方案吗?在函数完成之前显式释放锁的某种方法?或者运行某种子事务(可能通过在单独的函数中运行每个更新)?
更新
我接受了没有解决方案。我将每个更新写入一个单独的函数并从数据库外部进行协调。谢谢大家。
答案 0 :(得分:6)
没办法。 Postgres中的函数是原子的(总是在事务中),并且在事务结束时释放锁。而且还没有自主交易。
您可以使用advisory locks解决此问题。但那些不是一回事。所有竞争交易都必须发挥作用。不知道建议锁定的并发访问将破坏该方。
dba.SE上的代码示例:
或者你可能会在某些地方与dblink一起“欺骗”自治交易:
或者您重新评估您的问题并将其拆分为几个单独的交易。
答案 1 :(得分:1)
不可能。来自文档:一旦获得,通常会持有锁定直到交易结束。但是,如果在建立保存点后获取锁定,则在保存点回滚到的情况下立即释放锁定。这与ROLLBACK取消自保存点以来命令的所有效果的原则一致。对于在PL / pgSQL异常块中获取的锁也是如此:从块释放锁的错误逃脱释放在其中获取的锁。
http://www.postgresql.org/docs/9.3/static/explicit-locking.html
答案 2 :(得分:1)
在pg11中,您现在拥有PROCEDURE
,可以通过COMMIT
释放锁。我刚刚转换了一堆运行ALTER TABLE ... ADD FOREIGN KEY ...
的并行执行函数,但遇到了很多死锁问题,而且效果很好。
https://www.postgresql.org/docs/current/sql-createprocedure.html