项目上线,准备验收前出现了一个严重的问题:不少select语句做为死锁的牺牲,大部分报表没法打开。这个问题影响范围很大全部的报表都没法访问,而咱们的报表是放在电视上面轮播的,电视放在工厂里面,因此出现问题后,整个工厂都知道了。html
解决这个问题比较曲折,首先是写SAP接口的同事发现了问题:SAP一直在传错误数据致使产量表被锁住。修改SAP传输的错误数据后,这个死锁的问题没有出现了。可是我查看生产环境服务器日志的时候,发现这个问题依然存在,因为客户没有提这个问题,我也就是没有理由要求花时间修改了,由于我还有其余项目在忙。sql
问题始终存在,它的暴露只是时间问题。过了一周,在咱们要谈项目验收的时候,这个问题又暴露出来了。由于影响很是大,给客户形成很差的印象。因此修改这个问题获得了老板的支持,说实话,我也头一次遇到这样的问题,也想不通select语句怎么就死锁了。我知道这个问题很头疼,好在获得老板的支持,会给足够的时候我来解决问题,我也就有信心了。数据库
在网上找了不少文章,个人解决思路是:经过查询语句查找死锁相关的sql语句,只发现了被牺牲的那条sql语句,另一条sql语句没有找到,这条路走不通。接着就是重现问题,而后解决问题。这条路刚开始也走不通,也行不通,重现了一个下午有没有发现问题。在快下班的时候,我迷茫了。次日又网上找了半天资料,这个时候想到用sql server profiler去监听数据库,悲剧的是客户那边放假了,连不到出问题的生产环境数据库。接着跟同事聊这个问题,他给的建议依然是重现,而后记得有个方法能够重现,这个时候我才猛然想起来了有这档子事。服务器
重现方法是有sql语句循环往产量表插入数据,因为报表大多读取产量表,而后报表就常常死锁。这个时候我看到但愿了,只是不理解select语句怎么会引发死锁,后来在网上认真读了一篇文章:SqlServer中select语句引发的死锁(http://www.csharpwin.com/csharpspace/11505r288.shtml),读懂这篇文章后我以为跟我遇到的状况很是类似。spa
经过他的理论我分析了下死锁过程:版本控制
使用基于行版本控制的隔离级别:当在基于行版本控制的隔离下运行的事务读取数据时,读取操做不会获取正被读取的数据上的共享锁(S 锁)日志
if(charindex('Microsoft SQL Server 2008',@@version) > 0) begin declare @sql varchar(8000) select @sql = ' ALTER DATABASE ' + DB_NAME() + ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE ; ALTER DATABASE ' + DB_NAME() + ' SET READ_COMMITTED_SNAPSHOT ON; ALTER DATABASE ' + DB_NAME() + ' SET MULTI_USER;' Exec(@sql) end
很神奇,这样设置后,死锁的问题就不存在了。code
查询是否设置成功:
select is_read_committed_snapshot_on from sys.databases where name = DB_Name() server