公司的项目中遇到一个问题,以前解决过,不过忘记了具体的内容,所以记录一下。
场景:
压力环境下,不断在对数据库中的A表进行数据插入和更新;同时,为减轻数据库查询压力,所以开发人员对该表做了一个全缓存,每隔5分钟获取一次。这个时候就出现问题了:
因为在读取同时,该表也正在做更新操作,而更新操作会导致那行记录被加锁,所以当SELECT到那行记录的时候会引发锁冲突异常。
解决办法是:
SELECT COUNT(*) FROM table WITH (NOLOCK)
或者修改更新语句为:
UPDATE TABLE WITH (ROWLOCK)SET…
更为详细的内容引用别人的文章:
NOLOCK的使用
NOLOCK可以忽略锁,直接从数据库读取数据。这意味着可以避开锁,从而提高性能和扩展性。但同时也意味着代码出错的可能性存在。你可能会读取到运行事务正在处理的无须验证的未递交数据。 这种风险可以量化。
如果是金融方面的代码或者一些非常规的总计(你想绝对保证安全性),你应该小心行事并且不使用这种技术。 但是我认为使用该技术会比你90%应用系统性能要好,当用户(或者是交互代码)发现一个未递交的修改时,使用技术会保证不会像未使用该技术那样引起大麻烦。实际上,你可能发现你的大多数数据很少或者甚至不进行 修改的,这样我们就不会因为这些数据被锁住而浪费大量的时间。
例如,如果你想统计在2000年6月份到8月份之间加入Streamload.com的所有用户,就没有理由去锁住任何记录: 2000年9月1号一到来,这个用户数就是确定的。又例如要列举在Streamload.com的文件列表:这种结果即使 不是100%的正确,也不是大问题。因为你要么不拥有该文件,当然也无所谓你是否能找到它,或者你确实拥有该文件,这种情况下你当然知道你是否修改了该文件,以及该文件是否已经上传完毕了。
但是,如果这些数据的修改,对数据库来说是基础性的修改,或者这些数据对于用户来说,必须是百分之百保证 是修改正确的(例如帐单或者余额数据),那么你不要使用该技术。
ROWLOCK的使用
ROWLOCK告诉SQL Server只使用行级锁。ROWLOCK语法可以使用在SELECT,UPDATE和DELETE语句中,不过 我习惯仅仅在UPDATE和DELETE语句中使用。如果在UPDATE语句中有指定的主键,那么就总是会引发行级锁的。但是当SQL Server对几个这种UPDATE进行批处理时,某些数据正好在同一个页面(page),这种情况在当前情况下 是很有可能发生的,这就象在一个目录中,创建文件需要较长的时间,而同时你又在更新这些文件。当页面锁引发后,事情就开始变得糟糕了。而如果在UPDATE或者DELETE时,没有指定主键,数据库当然认为很多数据会收到影响,那样 就会直接引发页面锁,事情同样变得糟糕。
通过指定使用行级锁,这种情况可以得到避免。但是需要小心的是,如果你错误地使用在过多行上,数据库并不会聪明到自动将行级锁升级到页面锁,服务器也会因为行级锁的开销而消耗大量的内存和CPU,直至无法响应。尤其主要留意的是 企业管理器中"管理/当前活动"(Management/Current Activity)这一项。该项会花较长的时间来载入锁的信息。这些信息 时十分有用的,当你使用行级锁后,你如果在"锁/处理"(Locks/Processes)下看到几百个锁,一点都不奇怪,而恰恰应该庆幸锁超时和死锁的问题减少了。
注意事项
我认为SQL Server倾向于使用NOLOCK关键字,而ROWLOCK关键字由用户根据情况自行决定。你可以仅仅在 SELECT语句中使用NOLOCK,这些SELECT语句场合包括INNER查询,以及在INSERT语句中的SELECT使用,在连接查询下也可以使用,例如:
SELECT COUNT(Users.UserID)
FROM Users WITH (NOLOCK)
JOIN UsersInUserGroups WITH (NOLOCK) ON
Users.UserID = UsersInUserGroups.UserID
NOLOCK 和 ROWLOCK的使用效果
很难去量化在使用NOLOCK和ROWLOCK后,Streamload.com或者你的网站性能到底改善了多少。 不过在使用NOLOCK和ROWLOCK前,Streamload.com的速度很慢,而且经常无法使用,以及很不稳定。使用后,就变得快速、容易访问以及稳定了。两者简直就是天壤之别。这些改变当然无法在 关于锁的文档中很难找到。那些文档会建议你重写你的应用,当表数据被使用,锁产生了(没错,就是这样),然后你应该使用小事务并且以批处理的形式执行(不错,实际经验就是如此),使用低级别的隔离措施 (也没错,NOLOCK就是一个极端的例子),还建议你有限的连接,从而让处理器进行合作(好复杂的描述,而且总觉得怪怪的不像个好点子)。我不知道是否用数据库咨询师会提到本文中的技术(或类似的技术), 但是我只想说的是,Streamload.com的运行状况的确因为该技术得到了改善。如果你遇到了锁争用的问题,也可以试试NOLOCK和ROWLOCK。
申明
是否使用NOLOCK和ROWLOCK,需要自行判断,并谨慎运用。我用该技术的方法是通过查看我的存储过程和即时查询语句,在我自己的理解上来觉得哪里用和如何用。我需要判断如果用NOLOCK 而引起一些返回的不准确,或者ROWLOCK是否会造成太多的锁,这些情况出现时,对于访问者或者使用者来说,是否是可以接受的。在大多数情况下,我认为是没有问题的,但是也许你的代码不适用, 你需要小心对待。你需要创建一些独立的过程,是否加锁,如何加锁,以作为对比。当UPDATE或者 DELETE查询影响到很多数据行时,你在使用PAGELOCK,TABLOCK时也会遇到别的问题。
附:
SELECT Qty
FROM myTable WITH (UPDLOCK)
WHERE Id in (1,2,3)
UPDATE myTable SET Qty = Qty - A.Qty
FROM myTable AS A
INNER JOIN @_Table AS B ON A.ID = B.ID
COMMIT TRANSACTION --提交事务