Postgresql PL/pgSQL函数中检测到死锁

Postgresql PL/pgSQL函数中检测到死锁,postgresql,concurrency,deadlock,plpgsql,Postgresql,Concurrency,Deadlock,Plpgsql,我的PostgreSQL数据库中的PL/pgSQL函数面临死锁问题。请在代码块中找到SQL语句(仅为示例): 我发现在该语句运行期间发生了死锁。但我不确定是否有其他语句同时尝试更新此表(因为我在日志系统中没有找到任何语句) 那么,有没有可能死锁发生在这个语句中?据我所知,如果我们用BEGIN/END阻止整个语句。将有相同的事务,不应自行锁定。肯定有其他进程竞争相同的资源。这就是僵局的本质。像display这样的函数永远不会死锁。看,谁是PostgreSQL并发性方面的专家 缺少您的Postgre

我的PostgreSQL数据库中的PL/pgSQL函数面临死锁问题。请在代码块中找到SQL语句(仅为示例):

我发现在该语句运行期间发生了死锁。但我不确定是否有其他语句同时尝试更新此表(因为我在日志系统中没有找到任何语句)


那么,有没有可能死锁发生在这个语句中?据我所知,如果我们用
BEGIN
/
END
阻止整个语句。将有相同的事务,不应自行锁定。

肯定有其他进程竞争相同的资源。这就是僵局的本质。像display这样的函数永远不会死锁。看,谁是PostgreSQL并发性方面的专家

缺少您的PostgreSQL版本。现代版本会发出详细的错误消息。使用标准日志记录设置详细列出了争夺资源的两个进程。检查数据库日志

你发现错误的事实可能会妨碍Postgres向你提供全部细节。如果没有在数据库日志中获取信息,请从plpgsql函数中删除异常块,然后重试

为了缓解僵局,您可以做很多事情。如果所有客户端都以同步顺序访问资源,则不会发生死锁。本手册提供了解决本章中大多数情况的基本策略


< > <强>版本8.3 < /强>:考虑升级到一个更新近的版本。特别是,8.4版中的这一改进对您来说应该是有趣的():

报告死锁时,报告所涉及的所有查询的文本 服务器日志的死锁(Itagaki Takahiro)

此外,8.3版将满足其要求。你应该开始考虑升级。


涉及真空的死锁情况应该是。

在PostgreSQL中,begin表示启动批处理事务

您的第一次更新将锁定帐户
的行,其中帐户名为“A%”
这些行在第一次更新后以独占方式锁定

第二次更新尝试打开与第一次更新完全相同的行以进行更新 失败,因为第一次更新尚未提交


因此,第二次更新命中死锁是回滚

若添加commit以释放独占锁,就不会出现死锁问题

BEGIN
UPDATE accounts SET balance = 0 WHERE acct_name like 'A%';
COMMIT;  
UPDATE accounts SET balance = balance + 100 WHERE acct_name like '%A';
EXCEPTION WHEN OTHERS THEN RAISE NOTICE SQLERRM;
END;

你的帐户上有什么触发器吗?您还使用显式锁定吗?默认情况下,事务可以观察其他事务提交的更改。有关详细信息,请参阅PostgreSQL文档。@strkol是的,我有,但该触发器中的语句与此表无关。因为显式锁定也是肯定的。我有postgres 8.3.6。这句话只是举个例子。实际上,我使用insert log到另一个表来代替RAIST NOTIONE。通常,错误消息会提供您所需的信息。我对我的回答补充了一点。非常感谢你的建议。我将继续查找其他进程试图对该表执行的操作。无论触发器如何,事务本身都不会死锁。版本8.3.6在8.3生命周期中可能已经足够早了,一些前台进程和后台autovacuum进程之间存在交互的bug可能会死锁。更新到8.3.somethingrecent可能有助于消除这种可能性。计划在2月份8.3上线之前升级到新的主要版本也是明智的。在自动真空进程运行的同时更新表时,我们是否可以重新生成死锁发生的情况?plpgsql中的过程在单个事务提交块中运行,因此过程中没有提交。PL/pgSQL中的
BEGIN
只是代码块的开始。与普通SQL中的
BEGIN
/
COMMIT
不同。
BEGIN
UPDATE accounts SET balance = 0 WHERE acct_name like 'A%';
COMMIT;  
UPDATE accounts SET balance = balance + 100 WHERE acct_name like '%A';
EXCEPTION WHEN OTHERS THEN RAISE NOTICE SQLERRM;
END;