公司数据库随着时间的增加,数据愈来愈多,查询速度也愈来愈慢。进数据库看了一下,几十万调的数据,查询起来确实很费时间。html
要提高SQL的查询效能,通常来讲你们会以创建索引(index)为第一考虑。其实除了index的创建以外,当咱们在下SQL Command时,在语法中加一段WITH (NOLOCK)能够改善在线大量查询的环境中数据集被LOCK的现象藉此改善查询的效能。数据库
不过有一点千万要注意的就是,WITH (NOLOCK)的SQL SELECT有可能会形成Dirty Read,就是读到无效的数据。服务器
下面对于SQLSERVER的锁争用及nolock,rowlock的原理及使用做一个简单描述:并发
锁争用的描述性能
那些不只仅使用行级锁的数据库使用一种称为混和锁(lock escalation)的技术来获取较高的性能。除非很明确知道是针对整个数据表,不然这些数据库的作法是开始使用行级锁, 而后随着修改的数据增多,开始使用大范围的锁机制。测试
不幸的是,这种混和锁的方法会产生和放大新的问题:死锁。若是两个用户以相反的顺序修改位于不一样表的记录,而这两条记录虽然逻辑上不相关, 可是物理上是相邻的,操做就会先引起行锁,而后升级为页面锁。这样, 两个用户都须要对方锁定的东西,就形成了死锁。spa
例如:scala
用户A修改表A的一些记录,引起的页面锁不光锁定正在修改的记录,还会有不少其它记录也会被锁定。code
用户B修改表B的一些记录,引起的页面锁锁定用户A和其它正在修改的数据。htm
用户A想修改用户B在表B中锁定(并不必定正在修改的)数据。
用户B想修改或者仅仅想访问用户A在表A中锁定(并不必定正在修改)的数据。
为了解决该问题,数据库会常常去检测是否有死锁存在,若是有,就把其中的一个事务撤销,好让另外一个事务能顺利完成。通常来讲,都是撤销 那个修改数据量少的事务,这样回滚的开销就比较少。使用行级锁的数据库 不多会有这个问题,由于两个用户同时修改同一条记录的可能性极小,并且因为极其偶然的修改数据的顺序而形成的锁也少。
并且,数据库使用锁超时来避免让用户等待时间过长。查询超时的引入也是为了一样目的。咱们能够从新递交那些超时的查询,可是这只会形成数据库的堵塞。若是常常发生超时,说明用户使用SQL Server的方式有问题。正常状况是不多会发生超时的。
在服务器负载较高的运行环境下,使用混合锁的SQL Server锁机制,表现不会很好。 缘由是锁争用(Lock Contention)。锁争用形成死锁和锁等待问题。在一个多用户系统中,不少用户会同时在修改数据库,还有更多的用户在同时访问数据库,随时会产生锁,用户也争先恐后地获取锁以确保本身的操做的正确性,死锁频繁发生,这种情形下,用户的心情可想而知。
确实,若是只有少许用户,SQL Server不会遇到多少麻烦。内部测试和发布的时候,因为用户较少,也很难发现那些并发问题。可是当激发几百个并发,进行持续不断地INSERT,UPDATE,以及一些 DELETE操做时,如何观察是否有麻烦出现,那时候你就会手忙脚乱地去解锁。
锁争用的解决方法
SQL Server开始是用行级锁的,可是常常会扩大为页面锁和表锁,最终形成死锁。
即便用户没有修改数据,SQL Server在SELECT的时候也会遇到锁。幸运的是,咱们能够经过SQL Server 的两个关键字来手工处理:NOLOCK和ROWLOCK。
它们的使用方法以下:
SELECT COUNT(UserID) FROM Users WITH (NOLOCK) WHERE Username LIKE 'football'
和
UPDATE Users WITH (ROWLOCK) SET Username = 'admin' WHERE Username = 'football'
NOLOCK的使用
NOLOCK能够忽略锁,直接从数据库读取数据。这意味着能够避开锁,从而提升性能和扩展性。但同时也意味着代码出错的可能性存在。你可能会读取到运行事务正在处理的无须验证的未递交数据。 这种风险能够量化。
ROWLOCK的使用
ROWLOCK告诉SQL Server只使用行级锁。ROWLOCK语法可使用在SELECT,UPDATE和DELETE语句中,不过 我习惯仅仅在UPDATE和DELETE语句中使用。若是在UPDATE语句中有指定的主键,那么就老是会引起行级锁的。可是当SQL Server对几个这种UPDATE进行批处理时,某些数据正好在同一个页面(page),这种状况在当前状况下 是颇有可能发生的,这就象在一个目录中,建立文件须要较长的时间,而同时你又在更新这些文件。当页面锁引起后,事情就开始变得糟糕了。而若是在UPDATE或者DELETE时,没有指定主键,数据库固然认为不少数据会收到影响,那样 就会直接引起页面锁,事情一样变得糟糕。
下面写一个例子,来讲明一下NOLOCK的做用,这里使用一个有一万多条的数据库来测试,先不用NOLOCK来看一下:
declare @start DATETIME; declare @end DATETIME; SET @start = getdate(); select * from Captions_t18; SET @end = getdate(); select datediff(ms,@start,@end);
这里为了是效果更加明显,使用了Select * ,来看一下执行结果,以下图:
这里显示的使用时间是34720ms,下面使用NOLOCK来看一下:
declare @start DATETIME; declare @end DATETIME; SET @start = getdate(); select * from Captions_t18 with (NOLOCK); SET @end = getdate(); select datediff(ms,@start,@end);
运行结果以下图:
此次使用的时间是2563ms,差距体现出来了吧。我的感受时间不该该差这么多,总之性能是提升了很多。你们多多测试看看吧~~
参考文章:http://blog.sina.com.cn/s/blog_7034dbe00100ll9n.html