死锁的现象

编程

使用SqlServer的时候发现在高并发情况下,频繁更新和频繁查询引发死锁。通常我们知道如果两个事务同时对一个表进行插入或修改数据,会发生在请求对表的X锁时,已经被对方持有了。由于得不到锁,后面的Commit无法执行,这样双方开始死锁。


select语句使用非聚集索引查询产量信息,会对非聚集索引添加共享锁,由于非聚集索引上没有select的全部数据列,(所以会有书签查找出现,)需要查询产量表。查询产量表时,需要对产量表数据添加共享锁,需要等待Update语句更新完产量表后释放排他锁。即Select待Update释放锁。
此时产量表上的Update/Insert语句更新产量信息的时候,会在聚族索引上做定位,添加排他锁和修改非聚族索引的信息,问题就出在修改非聚族索引信息的时候,需要对非聚族做索引添加排他锁。此时select语句已经在聚族索引上面添加了共享锁,需要释放后才能被添加排他锁。即update语句需要等待select语句是否锁。这样死锁就形成了。

update的时候,它会申请一个针对clustered index的X锁的。

某个query使用非聚集索引来select数据,那么它会在非聚集索引上持有一个S锁。当有一些select的列不在该索引上,它需要根据rowid找到对应的聚集索引的那行,然后找到其他数据。而此时,第二个的查询中,update正在聚集索引上忙乎:定位、加锁、修改等。但因为正在修改的某个列,是另外一个非聚集索引的某个列,所以此时,它需要同时更改那个非聚集索引的信息,这就需要在那个非聚集索引上,加第二个X锁。select开始等待update的X锁,update开始等待select的S锁,死锁。

死锁的查看方法:

SELECT request_session_id spid, OBJECT_NAME( resource_associated_entity_id )

tableName FROM sys.dm_tran_locks WHERE resource_type = "OBJECT"

spid :被锁进程ID。 tableName:发生死锁的表名。

下面的方法,有助于将死锁减至最少(详细情况,请看SQLServer联机帮助,搜索:将死锁减至最少即可)。
按同一顺序访问对象。
1、避免事务中的用户交互。
2、保持事务简短并处于一个批处理中。
3、使用较低的隔离级别。
4、使用基于行版本控制的隔离级别。
     -将 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON,使得已提交读事务使用行版本控制。
     -使用快照隔离。
5、使用绑定连接。

6、使用nolock去掉共享锁,但死锁发生在u锁或x锁上,则nolock不起作用
7、升级锁颗粒度(页锁,表锁), 以阻塞还代替死锁
8、优化索引,避免全表扫描,减少锁的申请数目

以上是 死锁的现象 的全部内容, 来源链接: utcz.com/z/510686.html

回到顶部