0

我们在 SQL Server 中遇到“死锁”问题,其中不涉及显式锁,并且想知道如何绕过它们。

一些相关的背景信息:我们的应用程序非常古老且庞大。我们最近开始消除一些阻碍并发的问题,因此我们踏上了 SQL Server 上的死锁问题。我们没有资源来处理应用程序中的每个 select 语句,但正在寻找配置级别的更通用方法。

我们可以将一个示例性问题简化如下:基本上,我们有两个实体,EntityA并且EntityB。两者都映射到 SQL Server 架构中的各个表。在这两个实体之间,存在 am:n 关系,通过一个AToB表在数据库中映射,该表包含一些额外的上下文(即,AToB对于相同的AB.

在一个业务操作期间,一个新的实例AB被插入到数据库以及表中的多个条目AToB中。稍后在同一事务中再次读取所有这些数据(没有 for update)。在并行执行此操作时会发生死锁。这些死锁链接到AToB表。

比如说,我们有A1and B1,它们通过A1B1_1andA1B1_2A2and链接B2,它们通过A2B2_1and链接A2B2_2。我的猜测是会发生以下情况:

t1 -> INSERT A1
t1 -> INSERT B1
t1 -> INSERT A1B1_1 (PAGE1)
t2 -> INSERT A2
t2 -> INSERT B2
t2 -> INSERT A2B2_1 (PAGE1)
t1 -> INSERT A1B1_2 (PAGE2)
t2 -> INSERT A2B2_2 (PAGE2)
t1 -> SELECT * FROM AToB WHERE AToB.A=A1
t1 -> SELECT * FROM AToB WHERE AToB.A=A2

AToB现在,在对表的并发读取期间,t1获得了一个锁PAGE1t2获得了一个锁,PAGE2导致死锁。

第一个问题:这是发生僵局的合理解释吗?

第二个问题:在研究过程中给我的印象是,索引AToB.A可能会迫使 SQL Server 锁定表上的较少条目(甚至可能将其减少为一行,而不是页锁)。这是正确的吗?

第三个问题:我进一步的印象,这个问题可以通过snapshot-locking来解决。那正确吗?

我们尝试了这种方法,但是它把我们带入了下一个地狱循环:在业务事务期间,有一次业务标识符被分配给A. 这来自一个单独的表,它在As 中必须是唯一的。不可能通过数据库序列来分配它。我们的解决方案是通过第四个表上的select/来分配这个标识符。这是通过语句完成的。当采用快照锁定时,此锁定在获取期间被忽略,并且只会在提交期间导致乐观锁定异常。这导致我们updateIdentifierfor updatefor update

第四个问题:当使用快照锁定时,是否仍然有特殊事务仍然运行在悲观锁定上,或者是否可以告诉 SQL Server,某些表被排除在乐观锁定之外?

4

0 回答 0