分类目录

链接

2018年一月
« 12月   2月 »
1234567
891011121314
15161718192021
22232425262728
293031  

近期文章

热门标签

博主推荐

现在位置:    首页 > MySQL, SQL Server, 运维 > 正文
记一次sql server数据库死锁的解决过程
MySQL, SQL Server, 运维 暂无评论 阅读(259)

问题

客户说,数据同步失败了

背景

一个数据同步程序,windows service,从一台mysql的服务器A同步到另外一台sql server 2008r2的服务器B,5秒同步一次

同步过程

根据需求,因为新数据产生的数量不是很大,所以每5秒从中间临时表取出新数据ID,同步程序循环ID同步数据到sql server并删除临时表ID。

发现问题

远程上服务器,先查看进程管理员,sql server cpu 90-98%,明显sql server出问题了,问题在哪先不管。问了下客户,可不可以重启数据库,耽误1分钟(其实只需要10秒,防止意外,必须这样说)。

重启sql server后,问题仍然没有解决,过一分,cpu 又100%

查看同步程序日志,虽然有成功的同步记录,但是报了大量的错:

ExceptionMessage:Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.

大意是,执行超时?不应该啊,这个同步一条数据的过程一般不过超过1秒才对,怎么会超时?

执行了一下select语句:

select * from xxx
select * from xxx(nolock)
select count(0) from xxx

均正常。

因为我的错误日志里面,把发生错误的整个sql语句都是记录下来了的,于是执行sql语句,不报错,但是一直处于执行等待中(至少5秒+),,,,没事,当你看到这个的时候,你能想到的应该是两个字:死锁

没错,应该是死锁了。执行死锁查询:

selectrequest_session_id spid,OBJECT_NAME(resource_associated_entity_id) tableName 
fromsys.dm_tran_locks whereresource_type='OBJECT'
报出了 200多个死锁记录,不贴图了。

逐个杀死进程不太理想,所以下面这段代码也用不上了。

  1. --关闭进程
  2.  
  3. declare @spid int
  4. Set @spid = xxx --锁表进程
  5. declare @sql varchar(1000)
  6. set @sql='kill '+cast(@spid as varchar)
  7. exec(@sql)

 

 

分析问题

因为现在程序同步不了,所以,我停止了同步程序的windows 服务。

观察cpu,正常了。问题出在同步程序!

同步程序怎么会生产死锁呢?

我继续查看日志,看到一条信息,待同步的数据69条。

立马清晰了,应该是5秒内65条数据同步未完成,第二次同步就又开始了。因为我的同步程序使用了事务提交(避免数据不一致、脏数据),所以,应该是在第一轮同步数据在同步第N条数据时,第二次同步又开始了,造成了死锁。

 

解决问题

找到问题就简单了。

停止同步服务,修改同步间隔时间。修改为100秒,重启同步服务,等这70条数据同步完成再说。

大概不到1分钟的样子,我看日志,显示未同步的数量为0时,我重新停止同步服务,修改时间为5秒,重启同步服务。

一切OK!

总结

1.没有考虑到突发的数据来源(比如客户导入数据),或者同步程序很长时间未同步(人为关闭、断电、断网等),等可以同步时会产生大量未同步的数据,造成问题

2.程序不严禁,在第一同步未完成时,开始了第二轮同步。应该做一个判断

3.论日志的重要性。

本文版权归数据库之家所有,转载引用请完整注明以下信息:
本文作者:Bruce
本文地址:记一次sql server数据库死锁的解决过程 | 数据库之家