某现场报一个SQL死锁,于是开启了1222跟踪:
一段时间之后拷贝ERROR文件查找相关信息,比较有用的摘录出来如下:
语句一:
语句二:
相关的死锁资源如下:
可以明显的看到是select语句与insert语句产生了死锁,争用的资源分别6996和11086这两个page,这里比较奇怪因为sqlserver在默认隔离级别下,select操作会迅速释放页上的S锁,因此不存在形成死锁的基础--不可剥夺条件。
但其实这里是一种形成死锁的典型条件,参考宋大神的一幅图这里:--由书签查找产生的死锁。
其原理为:
1.由最初的update语句产生数据页A的IX锁,更新完毕后要请求索引页B的IX锁以便更新索引,但此时B页上已有与IX不兼容的S锁。
2.而select语句在索引页B上加了S锁后,正要通过书签查找获取数据页A的数据,要获取A页就要在A页上暂时加S锁,但A页又被update语句加了不兼容的IX锁,因此两个进程形成环路等待----死锁。
根据死锁的产生原理决定进行以下优化:
1.优化select语句使其尽快完成以减少死锁频率。
2.对select语句使用nolock选项以避免死锁问题。
3.通知开发优化相关代码的执行顺序来避免死锁问题。
最终优化了select语句,其他两条交给开发做修改。