记一次sqlserver 死锁排查exchangeEvent

记一次系列再更新,这次是死锁~

数据库死锁这个东西,一般碰到这个都会觉得头皮发麻,不知道怎么处理,

然后看了几篇文章以及sqlserver的官方文档后往往都会很蒙蔽,根本不知道在说什么

但是在最近的一次死锁中,我逐渐明白了一些,在这里分享下 

死锁原因:

不仅是数据库死锁,任何多线程都会死锁,而原因其实都是一个,那就是两方或两方以上资源竞争僵持不下,就一直相互等待,没错,2方以上也可以,这里拿现实点的比喻,

有2个盲盒A和B,每个盒子只有一个口子允许拿手进去摸

这里设置个条件,伸手去摸的盒子没法看,正在看的盒子不能摸,

摸盒子都是先看(add S)再摸(release S,add IX,add U -> X),最后在放手(release X,release IX)

同时

小张摸了A盒准备去摸B,看向了B,

小王摸了B盒准备去摸A,看向了A,

如果2人都一根筋都必须摸另一个盒子,那是不是就僵持了

因为

小张控制着A,准备去看B发现B没法看因为被小王控制着,然后小张一直等待着B被释放

小王控制着B,想去看A,发现A也没法看,因为被小张控制着,然后小王也等待着A被释放

然后这2个人,就一直等了(deadlock) 

死锁分析:

上面的例子其实就是数据库中出现的最标志性,最明显的死锁

小王和小张可以理解成2个请求

A和B就是2张表,这里涉及了加锁和解锁

涉及2个比较重要的锁,其他类型锁具体的可以看sqlserver的官方文档

共享锁S

这个锁就是查数据时候加的锁,加上这个锁以后,锁的资源能查,但不能修改,查询完释放S锁

排他锁X

这个锁是在数据进行insert,update,delete时候加的锁,加上这个锁以后,因为与其他锁不兼容,无法给这个资源加上别的锁,除非nolock或未提交读隔离级别

是不是可以理解成上面的条件(伸手去摸的盒子没法看,正在看的盒子不能摸)

下面说下我这次碰到的死锁

是在执行一条delete语句的时候触发的死锁,

死锁的另一条语句是一条insert语句,都是操作的同一张表,说实话一开始真的奇怪,这都能死锁。

先看了下死锁的2个锁一个是U锁,另一个是表面看是IX锁?,这个很奇怪,

然后查了下这2条语句的执行计划,发现死锁的表是有索引的,insert语句是正常的,delete语句发现delete筛选的字段有的有索引,有的没索引,导致bookmark lookup

https://blog.csdn.net/u012752975/article/details/22412915 和这篇里面的一个很像

但还是想不通为什么会死锁,并且把每条语句单独执行,通过SQL Server Profiler查了下加锁过程,似乎很难发现什么

后面干脆写了个多线程代码,再加上jmeter看看能不能复现出这个死锁

经过多次测试和踩坑,最后还是没有复现出了这个死锁,但是复现出了别的死锁,然后通过保存死锁图形 (SQL Server Profiler)

复现出的死锁是锁了索引导致的,是多条delete语句导致的,基本都是一条deleteX锁了某个索引,然后准备U锁另一个索引,然后另一条delete语句反过来就导致了死锁,有的甚至出现了3方死锁,如下图这样的

记一次sqlserver 死锁排查exchangeEvent_第1张图片

记一次sqlserver 死锁排查exchangeEvent_第2张图片

然后我又仔细看了那天的死锁日志,把里面的每个信息仔细地又看了遍,

发现这个也是多方的死锁,但是堵塞的对象里面发现了exchangeEvent,这个是啥?

经过多次搜索后

https://dba.stackexchange.com/questions/282959/what-does-exchangevent-indicate-in-sql-deadlock-graph

https://support.microsoft.com/en-us/topic/kb4089473-better-intra-query-parallelism-deadlocks-troubleshooting-in-sql-server-2017-and-2016-c0cc8ac0-ae4f-966a-b6ed-29dfcd17972a

https://blog.csdn.net/weixin_34015336/article/details/89758416

发现Intra-Query Parallel Thread Deadlocks

解决方案都在帖子的里面,我这边是后面优化了bookmark lookup的sql语句的索引最后解决了这个问题

你可能感兴趣的:(sqlserver)