Database 执行批量更新和删除操作时避免PostgreSQL死锁

Database 执行批量更新和删除操作时避免PostgreSQL死锁,database,postgresql,concurrency,deadlock,database-deadlocks,Database,Postgresql,Concurrency,Deadlock,Database Deadlocks,我们有一个表,它没有对任何其他表的引用 ┬────────────┬─────────────┬───────────────┬───────────────╮ │id_A(bigint)│id_B(bigint) │val_1(varchar) │val_2(varchar) │ ╪════════════╪═════════════╪═══════════════╪═══════════════╡ 表的主键是id_a和id_B的组合 此表的读取和写入是高度并发的,并且该表有数百万行。 我们

我们有一个表,它没有对任何其他表的引用

┬────────────┬─────────────┬───────────────┬───────────────╮
│id_A(bigint)│id_B(bigint) │val_1(varchar) │val_2(varchar) │
╪════════════╪═════════════╪═══════════════╪═══════════════╡
表的主键是id_a和id_B的组合

此表的读取和写入是高度并发的,并且该表有数百万行。 我们有几个存储过程可以进行大规模更新和删除。这些存储过程主要由触发器和应用程序代码并发调用

操作通常如下所示,可以匹配数千条记录以进行更新/删除:

DELETE FROM table_name 
WHERE id_A = ANY(array_of_id_A)
AND id_B = ANY(array_of_id_B)

UPDATE table_name
SET val_1 = 'some value', val_2 = 'some value'
WHERE id_A = ANY(array_of_id_A)
AND id_B = ANY(array_of_id_B)
我们正在经历死锁,所有使用SELECT FOR UPDATE和表级锁执行行级锁操作的尝试似乎都无法解决这些死锁问题。请注意,由于性能影响,我们不能以任何方式在此表上使用访问独占锁定

有没有其他方法可以尝试解决这些死锁情况

针对死锁的最佳防御通常是通过 确保所有使用数据库的应用程序都在 以一致的顺序排列多个对象

但在上述场景中,我们如何实现这一点呢。是否有一种保证按特定顺序执行批量更新插入操作的方法

在所有竞争查询的有序子查询中使用显式行级锁定。 SELECT不与写锁竞争

删去 从表中删除\u name t 使用 选择标识A、标识B 从表\u名称 其中id\u A=id\u A的任意数组 id_B=id_B的任意数组 按id_A、id_B订购 更新 德尔 其中t.id\u A=del.id\u A t.id_B=del.id_B; 使现代化 更新表\u name t SET val_1='某些值' ,val_2='某些值' 从…起 选择标识A、标识B 从表\u名称 其中id\u A=id\u A的任意数组 id_B=id_B的任意数组 按id_A、id_B订购 无密钥更新-Postgres 9.3+ -用于更新-用于旧版本或关键列上的更新 upd 其中t.id_A=upd.id_A t.id_B=upd.id_B; 这样,行将按照手册中建议的一致顺序锁定

假设id_A、id_B从未更新过,即使是像这样罕见的角落病例并发症也不可能发生

虽然不更新键列,但可以使用较弱的。要求博士后9.3或更高版本


另一个缓慢而可靠的选择是使用竞争性交易。您必须为序列化失败做好准备,在这种情况下,您必须重试该命令。

感谢您的回复@Erwin。我使用了你的策略,但仍然处于僵局。我看不出这种方法有什么明显的错误。我希望这些行按顺序锁定。如果有更多的建议可以尝试,我们将不胜感激。@sanjayav:您是否分析了日志以了解实际涉及的关系和查询?也许你还有其他问题忘了调整?是否存在导致访问导致表无序的触发器?我的团队一直面临着僵局,对此我非常恼火,这就是问题所在,谢谢@ErwinBrandstetter!