With (nolock) 和 With (rowlock) 关键字

关系型数据库,如SQL Server,使用锁来避免多用户修改数据时的并发冲突。当一组数据被某个用户锁定时,除非第一个用户结束修改并释放锁,否则其他用户就无法修改该组数据。

有些数据库,包括SQL Server,用锁来避免用户检索未递交的修改记录。在这些系统中,如果用户A在修改一组记录,则其他用户只有等用户A修改完毕了,才能检索。

数据库在每个物理层上设置锁:记录行(row lock),数据页(page lock,上百万记录行),扩展页(extend lock,多个数据页),整个表,甚至整个数据库。有些数据库(如Oracle等) 只使用精细的行锁机制,而别的数据库,则使用在页面,扩展页,表和数据库上的较大范围的锁机制。大多数数据库,包括SQL  Server,同样支持行锁机制,但是经常使用的还是大范围锁机制。  这主要是因为管理锁需要付出高昂的代价。锁十分复杂而且数量很多,所以如果全都是  行锁的话,将是极为痛苦的:一百万行的数据更新就会轻易消耗巨大的内存,从而根本无法进行管理。

锁争用的描述

那些不仅仅使用行级锁的数据库使用一种称为锁升级(lock  escalation)的技术来获取较高的性能。除非很明确知道是针对整个数据表,否则这些数据库的做法是开始使用行级锁,  然后随着修改的数据增多,开始使用大范围的锁机制。

不幸的是,这种锁升级的方法会产生和放大新的问题:死锁。如果两个用户以相反的顺序修改位于不同表的记录,而这两条记录虽然逻辑上不相关, 但是物理上是相邻的,操作就会先引发行锁,然后升级为页面锁。这样,两个用户都需要对方锁定的东西,就造成了死锁。

例如:

用户A修改表A的一些记录,引发的页面锁不光锁定正在修改的记录,还会有很多其它记录也会被锁定。
用户B修改表B的一些记录,引发的页面锁锁定用户A和其它正在修改的数据。   
用户A想修改用户B在表B中锁定(并不一定正在修改的)的数据。 
用户B想修改或者仅仅想访问用户A在表A中锁定(并不一定正在修改)的数据。   
这个时候形成了死锁。

为了解决该问题,数据库会经常去检测是否有死锁存在,如果有,就把其中的一个事务撤销,好让另一个事务能顺利完成。一般来说,都是撤销 那个修改数据量少的事务,这样回滚的开销就比较少。使用行级锁的数据库 很少会有这个问题,因为两个用户同时修改同一条记录的可能性极小,而且由于极其偶然的修改数据的顺序而造成的锁也少。而且,数据库使用锁超时来避免让用户等待时间过长。查询超时的引入也是为了同样目的。我们可以重新递交那些超时的查询,但是这只会造成数据库 的堵塞。如果经常发生超时,说明用户使用SQL  Server的方式有问题。正常 情况是很少会发生超时的。

在服务器负载较高的运行环境下,使用锁升级的SQL  Server锁机制,表现不会很好。  原因是锁争用(Lock  Contention)。锁争用造成死锁和锁等待问题。在一个多用户系统中,很多用户会同时在修改数据库,还有更多的用户在同时访问数据库,随时会产生锁,用户 也争先恐后地获取锁以确保自己的操作的正确性,死锁频繁发生,这种情形下,  用户的心情可想而知。

确实,如果只有少量用户,SQL  Server不会遇到多少麻烦。内部测试和发布的时候,由于用户较少,也很难发现那些并发问题。但是当激发几百个并发,进行持续不断地INSERT, UPDATE,以及一些  DELETE操作时,如何观察是否有麻烦出现,那时候你就会不得不手忙脚乱地去阅读有关数据库的文献了。 不过我有一个解决办法,该方法只需要检查你的T-SQL代码,很少的调整和系统测试。用该方法教你进行适当的系统测试过程。

锁争用的解决方法 

如果你在访问某些网站时看到诸如“遇到死锁”,“锁超时”,“需要对象”等错误。这些错误都是由于锁争用引起的。

SQL  Server开始是用行级锁的,但是经常会扩大为页面锁和表锁,最终造成死锁。即使用户没有修改数据,SQL  Server在SELECT的时候也会遇到锁。幸运的是,我们可以通过SQL  Server  的两个关键字来手工处理:NOLOCK和ROWLOCK。

它们的使用方法如下:

SELECT  COUNT(UserID)  FROM  Users  WITH  (NOLOCK)  WHERE  Username  LIKE '%foobar' 
和 
UPDATE  Users  WITH  (ROWLOCK)  SET  Username  =  'fred' WHERE  Username  =  'foobar'

NOLOCK的使用

NOLOCK可以忽略锁,直接从数据库读取数据。这意味着可以避开锁,从而提高性能和扩展性。但同时也意味着代码出错的可能性存在。你可能会读取到运行事务正在处理的无须验证的未递交数据。 这种风险可以量化。

如果是金融方面的代码或者一些非常规的总计(你想绝对保证安全性),你应该小心行事并且不使用这种技术。但是我认为使用该技术会比你90%应用系统性能要好,当用户 (或者是交互代码)发现一个未递交的修改时,使用该技术会保证不会像未使用该技术那样引起大麻烦。实际上,你可能发现你的大多数数据很少或者甚至不进行修改的,这样我们就不会因为这些数据被锁住而浪费大量的时间。

例如,如果你想统计在2009年6月到8月之间某网站的注册用户,就没有理由去锁住任何记录: 2009年9月1号一到来,这个用户数就是确定的。

ROWLOCK的使用

ROWLOCK告诉 SQL  Server只使用行级锁。ROWLOCK语法可以使用在SELECT, UPDATE和DELETE语句中,不过 我习惯仅仅在UPDATE和DELETE语句中使用。如果在UPDATE语句中有指定的主键,那么就总是会引发行级锁的。但是当SQL  Server对几个这种UPDATE进行批处理时,某些数据正好在同一个页面(page),这种情况在当前情况下  是很有可能发生的,这就象在一个folder中,创建一个新文件需要较长的时间,而同时你又要去更新该folder中的某些文件。当页面锁引发后,事情就开始变得糟糕了。而如果在UPDATE或者DELETE时,没有指定主键,数据库当然认为很多数据会收到影响,那样 就会直接引发页面锁,事情同样变得糟糕。

通过指定使用行级锁,这种情况可以得到避免。但是需要小心的是,如果你错误地使用在过多行上,数据库并不会聪明到自动将行级锁升级到页面锁,服务器也会因为行级锁的开销而消耗大量的内存和CPU,直至无法响应。尤其主要留意的是 企业管理器中"管理/当前活动"(Management/Current  Activity)这一项。该项会花较长的时间来载入锁的信息。这些信息是十分有用的,当你使用行级锁后,你如果在"锁/处理"(Locks/Processes)下看到几百个锁,一点都不奇怪,而恰恰应该庆幸锁超时和死锁的问题减少了。

注意事项

我认为SQL  Server倾向于使用NOLOCK关键字,而ROWLOCK关键字由用户根据情况自行决定。你可以仅仅在  SELECT语句中使用NOLOCK,这些SELECT语句场合包括Join查询,以及在INSERT语句中的SELECT使用,例如:

SELECT  COUNT(U.UserID)  FROM  Users  U WITH  (NOLOCK) 
inner join  UsersInUserGroups  UG  WITH  (NOLOCK)  ON   U.UserID  =  UG.UserID

NOLOCK  和  ROWLOCK的使用效果

很难去量化在使用NOLOCK和ROWLOCK后,Streamload.com网站给我们了一个信息。 使用NOLOCK和ROWLOCK前,Streamload.com的速度很慢,而且经常无法使用,以及很不稳定。使用后,就变得快速、容易访问以及稳定了。两者简直就是天壤之别。这些改变当然无法在 关于锁的文档中很难找到。那些文档会建议你重写你的应用,当表数据被使用,锁产生了(没错,就是这样),然后你应该使用小事务并且以批处理的形式执行(不错,实际经验就是如此),使用低级别的隔离措施  (也没错,NOLOCK就是一个极端的例子),还建议你有限的连接,从而让处理器进行合作(好复杂的描述,而且总觉得怪怪的不像个好点子)。我不知道是否用数据库咨询师会提到本文中的技术(或类似的技术), 但是我只想说的是,Streamload.com的运行状况的确因为该技术得到了改善。如果你遇到了锁争用的问题,也可以试试NOLOCK和ROWLOCK。

申明

是否使用NOLOCK和ROWLOCK,需要自行判断,并谨慎运用。我用该技术的情况是:在并发性很高的数据库中select自己想要的数据。我需要判断如果用NOLOCK 而引起一些返回的不准确,或者ROWLOCK是否会造成太多的锁,这些情况出现时,对于访问者或者使用者来说,是否是可以接受的。在大多数情况下,我认为是没有问题的,但是也许你的代码不适用,你需要小心对待。你需要创建一些独立的过程,是否加锁,如何加锁,以作为对比。当UPDATE 或者  DELETE查询影响到很多数据行时,你在使用PAGELOCK, TABLOCK时也会遇到别的问题。

(0)

相关推荐

  • 涨姿势的52条SQL语句性能优化

    转自:cnblogs.com/SimpleWu/p/9929043.html 本文会提到 52 条 SQL 语句性能优化策略. 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 WHERE 及 O ...

  • final关键字在PHP中的使用

    final关键字的使用非常简单,在PHP中的最主要作用是定义不可重写的方法.什么叫不可重写的方法呢?就是子类继承后也不能重新再定义这个同名的方法. class A { final function t ...

  • Excel批量删除指定关键字Sheet名称的工作表,助力办公效率提升

    Excel情报局 Excel职场联盟 生产搬运分享Excel基础技能 Excel爱好者大本营 用1%的Excel基础搞定99%的职场问题 做一个超级实用的Excel公众号 Excel是门手艺玩转需要勇 ...

  • Java 中的关键字

    Java 中有多少个关键字,有大小写之分吗? Java 中有 48 个关键字在使用 + 两个保留关键字未使用,共 50 个关键字. Java 关键字全部都由是小写组成. Java 中保留关键字分别是哪 ...

  • Static关键字

    Static关键字 Static修饰的属性称为类变量,修饰的方法称为静态方法,类变量和静态方法可直接使用类名点变量名/方法名调用, 但实例变量(没有static修饰的属性)和非静态方法就必须通过new ...

  • C语言丨关键字union的定义和使用

    union,中文名"联合体.共用体",在某种程度上类似结构体struct的一种数据结构,共用体(union)和结构体(struct)同样可以包含很多种数据类型和变量. 但在&quo ...

  • Excel表格《像百度一样的搜索框》通过关键字来查找相应数据

    Excel表格《像百度一样的搜索框》通过关键字来查找相应数据

  • Python学习之常用关键字!

    你知道Python常用关键字有哪些吗?有哪些关键字是你不太了解的呢?今天小编通过这篇文章为大家介绍一下. 1.内置常量:False.none.True; >>> False == 0 ...

  • Android 字符串批量匹配关键字并高亮处理

    有一个需求,敏感词检测,App端将文本框输入的字符长串提交到后端,后端返回敏感词数组,前端输入框对敏感词关键字高亮处理. 第一步:从 字符串找出包含某关键字的所有地方.利用到的类:Pattern,Ma ...

  • 高考答题提分技巧丨化学审题审出关键字审出突破口

    高考进入倒计时,第三次模拟考试已经结束,为了最大限度助力考生提升高考成绩,本报联合哈师大附中优秀名师团队,在最后关键时刻,给出考生高考答题提分技巧.以下是化学学科. 指导名师:哈师大附中高三学年主任王 ...