当前位置: 代码迷 >> Sql Server >> 真没分了,但是又死锁了,该怎么解决
  详细解决方案

真没分了,但是又死锁了,该怎么解决

热度:78   发布时间:2016-04-24 10:18:47.0
真没分了,但是又死锁了
A线程,没开事务,同一个连接里面
语句1
Select * 
FROM TableA
LEFT JOIN TableB
语句2(死锁)
Select Count(*) 
FROM TableA
LEFT JOIN TableB

B线程
开事务
Insert into TableA
Insert Into TableB (死锁)
我没搞懂,我insert完了以后才提交事务的,
select又没有允许脏读什么的,为什么会死锁了呢?
------解决方案--------------------
1、insert也会锁
2、锁表和锁是不衡等的,不是每次都锁表。
3、insert锁表的顺序是先在表上加IX 在页上加IX ,在ROW上加X
4、SELECT COUNT会在所有页上加S锁,而你join会导致两个表都加S锁,锁的范围更广。
5、当线程Aselect 的时候,在两个表上加了S锁,线程B此时第一次INSERT,加IX锁,这个没问题。但是接下来线程A又一次SELECT ,由于S锁在默认隔离级别下select完就会释放,所以第二次select时再次加S锁,但是由于B对TableA加了IX锁,所以A线程不能对TableA加S锁。另外线程B在第一次insert的时候由于A/B两表有外键,所以B的对应数据上也会加IX锁,第二次insert 到B的时候IX和前面INSERT中B表上的IX不兼容,又需要等待,导致A、B两个线程都在等待。最终死锁。
这个好像有点乱。比较不好理解。

解决建议:
1、在A/B两表(不是线程)上的外键关联列,如果没有索引的话,加上一个非聚集索引
2、在A/B两表上,找出最窄的非NULL列,建一个索引。

------解决方案--------------------
引用:


对1楼的第2个死锁图进行简要说明:
===================================

1.根据图,先对他们作几个标记:
--------------------------
右边的椭圆:     进程103
左边的椭圆:     进程75
中间位置上边框: 资源37467
中间位置下边框: 资源36940


2.分析图,同一时间内存在下面两种情况:
-----------------------------------

a: 进程103对资源37467,持有1个意向独占锁(IX)    ,与此同时,进程75对资源37467,请求1个共享锁(S)
b: 进程75对资源36940,持有1个共享锁(S)          ,与此同时,进程103对资源36940,请求1个意向独占锁(IX)

3.使用二维表描述两个资源的状态:
-----------------------------------------
资源                  持有               请求
-----------------------------------------
资源37467     进程103(IX)    进程75(S)
资源36940     进程75(S)       进程103(IX)

4.由于在lock models中,IX锁和S锁是互斥,不兼容。简单说就是一个资源,存在了IX锁,不能再存在一个S锁,反之亦然;
在这里场景中,它们两个进程同时对两个资源各存在‘持有’和‘请求’的状态,
由于两个进程不会主动释放资源,它们会进入一个持有与请求的僵局。

5.sql server系统(boss),发现这样一个僵局,没办法,为了维持资源的可利用,对对立的双方进行仲裁,宣判其中一个进程作为牺牲品,另一进程继续作业。

  相关解决方案