Yur*_*uts 9 sql-server concurrency deadlock primary-key
我在SQL服务器中有一个表,它由在不同会话中同时运行的存储过程同时进行CRUD:
|----------------|---------|
| <some columns> | JobGUID |
|----------------|---------|
该程序的工作原理如下:
存储过程中的每个select/insert/update/delete语句都有一个WHERE JobGUID = @jobGUID
子句,因此该过程仅适用于它在步骤2中插入的记录.但是,有时当同一存储过程在不同的连接中并行运行时,会发生死锁共享表.以下是SQL Server Profiler的死锁图:
锁定升级不会发生.我尝试向(UPDLOCK, ROWLOCK)
所有DML语句添加锁定提示和/或在事务中包装过程的主体并使用不同的隔离级别,但它没有帮助.共享表上的RID锁定仍然相同.
之后我发现共享表没有主键/标识列.一旦我添加它,死锁似乎已经消失:
alter table <SharedTable> add ID int not null identity(1, 1) primary key clustered
Run Code Online (Sandbox Code Playgroud)
当我删除主键列时,死锁又回来了.当我把它添加回来时,我再也无法重现死锁了.
那么,问题是,主键身份列真的能够解决死锁还是巧合?
更新:作为@Catcall建议,我已经尝试创建现有列的自然聚集主键(无添加标识列),但还是抓住了相同的僵局(当然,这一次是一键锁定,而不是RID锁).
小智 4
解决死锁的最佳资源(仍然)在这里:http ://blogs.msdn.com/b/bartd/archive/2006/09/09/deadlock-troubleshooting_2c00_-part-1.aspx 。
\n\n第 4 部分说:
\n\n\n\n\n通过数据库优化\n Advisor 运行死锁中涉及的查询。将查询放入 Management Studio 查询窗口中,将数据库上下文更改为正确的数据库,右键单击查询文本并选择 \xe2\x80\x9c 在 DTA\xe2\x80\x9d 中分析查询。不要\xe2\x80\x99t跳过此步骤;我们看到的超过一半的死锁问题只需添加适当的索引即可解决,以便其中一个查询运行得更快并且锁占用空间更小。如果 DTA 建议索引(它会显示\n \xe2\x80\x9c预计改进:%\xe2\x80\x9d),请创建它们并监视\n以查看死锁是否仍然存在。您可以从“操作”下拉菜单中选择 \xe2\x80\x9c\n 应用建议\xe2\x80\x9d\n 以立即创建索引,或\n 将 CREATE INDEX 命令保存为脚本以在\n 维护期间创建索引窗户。请务必单独调整每个查询。
\n
我知道这并不能“回答”为什么一定如此,但它确实表明添加索引可以改变执行方式,使锁占用空间更小或执行时间更快,从而可以显着减少死锁的可能性。
\n