在SQL Server中,复合主键是否会增加死锁的可能性?

时间:2012-10-16 13:11:24

标签: sql sql-server

我想知道,或者是因为增加了行锁定,还是因为增加了持有锁的时间,在表上定义了复合主键会增加在更新时遇到死锁的可能性多个线程一次?

感谢您的帮助。

3 个答案:

答案 0 :(得分:5)

如果您正在使用复合PK并且并行插入大量数据,则可能会遇到资源哈希冲突。有关真实世界的示例,请参阅"The Curious Case of the Dubious Deadlock and the Not So Logical Lock"

对于资源哈希冲突的解释,我将在"%%lockres%% collision probability magic marker: 16,777,215"中引用Remus Rusanu(推荐阅读):

  

SQL Server中的锁管理器不知道它锁定了什么,它只是锁定'资源'(基本上是字符串)。这是更高级别组件的工作,例如存储引擎的访问方法,将“资源”呈现给锁管理器并请求所需的锁。当锁定堆或b树中的行时,存储引擎将从记录标识符合成“资源”。由于这些资源的长度有限,因此存储引擎必须将密钥的有效长度减少到允许向锁管理器提供的最大长度,这意味着记录的密钥将减少到6个字节。这是通过将密钥散列为6字节散列值来实现的。

[...]

  

在6个字节上有281,474,976,710,656个不同的可能值。这是一个相当大的数字?实际上并不是那么大。 [...]因此SQL %% lockres %%哈希将生成两个具有相同哈希值的记录,其中50%的概率在表中,任何表中只有16,777,215条记录。

答案 1 :(得分:3)

由于SQL Server的Lock Manager使用了lockhash值(而不是直接使用PK),因此我认为使用单列PK与复合PK的锁定没有区别。

Improvement in minimizing lockhash key collisions in SQL Server 2008R2 and its impact on concurrency

与其他一些数据库供应商不同,SQL Server的Lock Manager有一个逻辑组件。 SQL Server使用lockhash值来表示SQL Server Lock Manager中锁定结构的锁定,而不是使用对行,页面或表格的物理描述。然后lockhash值保存在内存中。

我认为从单个列密钥到复合密钥获取lockhash值的哈希冲突的可能性更大。如SQL 2008R2链接所示,lockhash得到了显着改进,并专门针对复合键。

在2008R2之前,对于单键和复合键,lockhash并不完美 保持PK短缺是一种很好的做法。

.NET KeyValuePair和Tuple不会生成好的哈希值。

答案 2 :(得分:2)

一般来说,我倾向于说不,它没有精心设计的代码。原因是死锁的原因和避免/消除它们的技术通常不依赖于时间。由于线程内的更新路径不同,大多数死锁都会发生。例如,代码A确实更新了Table1,然后更新了Table2,而代码块B更新了Table2,然后更新了Table1。用于避免这种情况的技术涉及确保各种代码块以相同的顺序尝试和更新项目。换句话说,避免线程1锁定A并想要更新B的情况,而线程2锁定B并想要更新A.

但是,如果存在这些冲突的编码块/语句,我认为复合键可以增加发生死锁的频率。基本上,事务完成所需的时间越长,另一个线程锁定其他资源并导致死锁的时间就越长。

除了一个非常小/特定的边缘情况,我不相信复合键会对死锁的发生产生影响(至少在我的经验中没有)。