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),发现这样一个僵局,没办法,为了维持资源的可利用,对对立的双方进行仲裁,宣判其中一个进程作为牺牲品,另一进程继续作业。