共计 2653 个字符,预计需要花费 7 分钟才能阅读完成。
SQL Server 中如何减少死锁,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
减少 SQLServer 死锁的方法有哪些
如事务 1 的线程 T1 具有表 A 上的排它锁,事务 2 的线程 T2 具有表 B 上的排它锁,并且之后需要表 A 上的锁。事务 2 无法获得这一锁,因为事务 1 已拥有它。事务 2 被阻塞,等待事务 1。然后,事务 1 需要表 B 的锁,但无法获得锁,因为事务 2 将它锁定了。事务在提交或回滚之前不能释放持有的锁。因为事务需要对方控制的锁才能继续操作,所以它们不能提交或回滚,这样数据库就会发生死锁了。
如在编写存储过程的时候,由于有些存储过程事务性的操作比较频繁,假如先锁住表 A,再锁住表 B,那么在所有的存储过程中都要按照这个顺序来锁定它们。假如无意中某个存储过程中先锁定表 B,再锁定表 A,这可能就会导致一个死锁。而且死锁一般是不太容易被发现的。
假如服务器上经常出现这种死锁情况,就会降低服务器的性能,所以应用程序在使用的时候,我们就需要对其进行跟踪,使用 sp_who 和 sp_who2 来确定可能是哪些用户阻塞了其他用户,我们还可以用下面的存储过程来跟踪具体的死锁执行的影响:
createproceduresp_who_lock
as
begin
declare@spidint,@blint,
@intTransactionCountOnEntryint,
@intRowcountint,
@intCountPropertiesint,
@intCounterint
createtable#tmp_lock_who(idintidentity(1,1),spidsmallint,blsmallint)
IF@@ERROR 0RETURN@@ERROR
insertinto#tmp_lock_who(spid,bl)select0,blocked
from(select*fromsysprocesseswhereblocked 0)a
wherenotexists(select*from(select*fromsysprocesseswhereblocked 0)b
wherea.blocked=spid)
unionselectspid,blockedfromsysprocesseswhereblocked 0
IF@@ERROR 0RETURN@@ERROR
– 找到临时表的记录数
select@intCountProperties=Count(*),@intCounter=1
from#tmp_lock_who
IF@@ERROR 0RETURN@@ERROR
if@intCountProperties=0
select’现在没有阻塞和死锁信息’asmessage
– 循环开始
while@intCounter =@intCountProperties
begin
– 取第一条记录
select@spid=spid,@bl=bl
from#tmp_lock_whowhereid=@intCounter
begin
if@spid=0
select’引起数据库死锁的是:’+CAST(@blASVARCHAR(10))+’进程号, 其执行的 SQL 语法如下’
else
select’进程号 SPID:’+CAST(@spidASVARCHAR(10))+’被’+’进程号 SPID:’+CAST(@blASVARCHAR(10))+’阻塞, 其当前进程执行的 SQL 语法如下’
DBCCINPUTBUFFER(@bl)
– 循环指针下移
set@intCounter=@intCounter+1
droptable#tmp_lock_who
return0
减少 SQLServer 死锁的方法有哪些
我们只需要通过在查询分析器里面执行 sp_who_lock,就可以具体捕捉到执行的堵塞进程,这时我们就可以对对应的 SQL 语句或者存储过程进行性能上面的改进及设计。[Page]
所以我们在数据库设计的时候,虽然不能完全避免死锁,但可以使死锁的数量尽量减少。增加事务的吞吐量并减少系统开销,因为只有很少的事务,所以就得遵循下面的原则:
按同一顺序访问对象
假如所有并发事务按同一顺序访问对象,则发生死锁的可能性会降低。在写 SQL 语句或存储过程的时候,就需要按照顺序在两个并发事务中先获得表 A 上的锁,然后获得表 B 上的锁,当第一个事务完成之前,另一个事务被阻塞在表 A 上。第一个事务提交或回滚后,第二个事务继续进行,而不能在语句里面写先获得表 B 上的锁,然后再获得表 A 的锁。
避免事务中的用户交互
避免编写包含用户交互的事务,因为运行没有用户交互的批处理的速度要远远快于用户手动响应查询的速度,例如答复应用程序请求参数的提示。例如,假如事务正在等待用户输入,而用户就去做别的事了,则用户将此事务挂起使之不能完成。这样将降低系统的吞吐量,因为事务持有的任何锁只有在事务提交或回滚时才会释放。即使不出现死锁的情况,访问同一资源的其它事务也会被阻塞,等待该事务完成。
保持事务简短并在一个批处理中
在同一数据库中并发执行多个需要长时间运行的事务时通常发生死锁。事务运行时间越长,其持有排它锁或更新锁的时间也就越长,从而堵塞了其它活动并可能导致死锁。保持事务在一个批处理中,可以最小化事务的网络通信往返量,减少完成事务可能的延迟并释放锁。
使用低隔离级别
确定事务是否能在更低的隔离级别上运行。执行提交读允许事务读取另一个事务已读取 (未修改) 的数据,而不必等待第一个事务完成。使用较低的隔离级别 (例如提交读) 而不使用较高的隔离级别 (例如可串行读) 可以缩短持有共享锁的时间,从而降低了锁定争夺。
使用绑定连接
使用绑定连接使同一应用程序所打开的两个或多个连接可以相互合作。次级连接所获得的任何锁可以象由主连接获得的锁那样持有,反之亦然,因此不会相互阻塞。
下面有一些对死锁发生的一些建议:
1)对于频繁使用的表使用集簇化的索引;
2)设法避免一次性影响大量记录的 T -SQL 语句,特别是 INSERT 和 UPDATE 语句;
3)设法让 UPDATE 和 DELETE 语句使用索引;
4)使用嵌套事务时,避免提交和回退冲突;
5)对一些数据不需要及时读取更新值的表在写 SQL 的时候在表后台加上(nolock),如:Select*fromtableA(nolock)。
看完上述内容,你们掌握 SQL Server 中如何减少死锁的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注丸趣 TV 行业资讯频道,感谢各位的阅读!