9

我想知道是否因为增加了行锁定和/或因为增加了持有锁所花费的时间,在表上定义复合主键会增加在更新我的多个线程时出现死锁的机会一次?

感谢您的任何帮助。

4

3 回答 3

6

如果您使用复合 PK 并并行插入大量数据,您可能会受到资源哈希冲突的影响。有关真实世界的示例,请参阅“可疑死锁和不太合乎逻辑的锁的奇怪案例” 。

对于资源哈希冲突的解释,我将在“%%lockres%% 冲突概率魔法标记:16,777,215”(推荐阅读)中引用 Remus Rusanu:

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

[...]

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

于 2012-10-16T13:38:53.323 回答
3

由于 SQL Server 的锁管理器使用 lockhash 值(而不是直接使用 PK),我会得出结论,使用单列 PK 与复合 PK 进行锁定没有区别。

减少 SQL Server 2008R2 中的 lockhash 密钥冲突及其对并发性的影响的改进

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

我会得出结论,从单列键与复合键中获得锁哈希值的哈希冲突的机会不会更大。如与 SQL 2008R2 的链接中所示,lockhash 得到了显着改进,并专门解决了复合键。

在 2008R2 之前,lockhash 对于单键和复合键都不够完美。
保持 PK 简短是一个好习惯。

.NET KeyValuePair 和 Tuple 不会生成好的散列。

于 2012-10-16T15:49:24.950 回答
2

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

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

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

于 2012-10-16T13:20:33.327 回答