不久前,我花了数周的噩梦来处理“检测到死锁”并试图弄清楚如何处理它。我最终以这样一种方式处理它,即我的代码能够检测到它何时发生,然后在每次重试之间以 50000 微秒无限期地重试相同的查询,直到它起作用。
也许这是不好的做法,但到目前为止(几个月),除了记录“检测到的死锁”所谓的“错误”之外,它没有引起任何问题。
我现在可以通过将“检测到死锁”错误标记为“不重要”来抑制“检测到死锁”错误,因此即使它们仍然登录到我的错误日志表中也不会向我显示?
请不要告诉我“首先避免它们”。这根本不可能。如果您在同一个表/事物上进行并发(多个进程/脚本实例),它们显然会发生。我一直在尝试“将它们编码”,但这似乎是不可能的。
显然,由于我问的是这个而不是仅仅添加忽略规则并完成它,我确实关心答案/响应。尽管如此,我认为目前我不能确信它们可以完全避免。我并不是说我每小时记录数千个或其他任何内容,而是每天记录一些,似乎总是在开始时我确实有很多并发进程在同一个表/查询上工作。
死锁是一种序列化错误:您没有做任何禁止的事情,只是碰巧与其他活动事务的交互阻止了您的事务完成。你的反应是正确的:重试交易。在重试之前绝对不需要等待。
我同意,对于较大事务的足够复杂的工作负载,几乎不可能完全排除死锁。只要它们很少发生,如果您正确处理它们,它们就不是真正的问题。
如果死锁发生得太频繁,它们就会开始成为一个问题:这意味着您必须重做大量工作,这对性能不利并且会给您的数据库带来额外的负载。此外,在解决死锁之前等待一秒意味着锁被持有很长时间(一秒很长),这对于并发性来说不是很好。
即使不能完全摆脱死锁,也可以采取措施减少死锁:
看到你的交易很短
尝试减少每个事务的数据修改次数
两者都将减少陷入僵局的可能性。
忽略日志文件中的死锁错误是安全的,但是您应该监控
pg_stat_database.deadlocks
每小时死锁计数增加超过可接受的数量并采取措施。您看到反对将死锁称为错误。根据定义,错误是中止 SQL 语句执行的条件。所以死锁显然是一个错误。