王老师讲解:SQL Server 2005数据库nolock的使用【来自Aisino_BBS】

前两天去安徽航天信息解决A6系统的性能问题,去之前进销存项目组研发人员小苏和小卢把他们认为性能
有问题的SQL已经发给了我,我把优化方法提交给了他们。本以为到那之后会非常轻松,但还是有些插曲在其中。
    到安徽航天信息后,我检查操作系统和数据库日志、服务器配置,通过性能监视器查看CPU、内存和磁盘I/O
情况。安徽航信的技术人员把临时补丁打上后,统计分析--销售收入明细列表的执行时间在2~3秒,他们很满意,
  销售管理-帐表查询-销售发票明细的执行时间还是不令人满意,更要命的是一但有人查询销售发票
明细,其他人查询就会被挂起......。销售发票明细查询出来后,其它查询才会查出结果。很明显
没有出现死锁,一定是这个查询阻塞了其它查询。
    通过查询sysprocesses和sys.dm_exec_sql_text视图,发现引起阻塞的进程所执行的SQL语句是:
select tempTable_.* into tempTable_556975850345921751 from ( select......)被阻塞的进程
执行的语句可能是select cguid code,cName name,cOften from PT_QueryPlan where cFormID =@P0
and cOrgnId=@P1 and (cUserID=@P2 or cType='s') and cOften='1' order by cName。select语句
一般情况下会在被查询对象上加共享锁,共享锁不会阻止其它语句加共享锁,事情有些怪异了。
    据本人的经验,引起阻塞的语句一定在现在执行的语句之前执行的语句,那条语句的执行修改了
某个表的数据,在没有提交前导致了这个select cguid code,cName name,cOften from PT_QueryPlan
无法完成,这个表应该就是PT_QueryPlan了!
    回公司后和平台研发人员沟通,了解到使用临时表进行查询的大致过程是1)执行上面这个语句,
查询PT_QueryPlan中有无当前用户相应的查询方案?2)根据查询结果修改PT_QueryPlan或向该表中插
入相应数据;3)执行select tempTable_.* into tempTable_XXXXXXXXXXXXX from ( select......)
正是由于这条插入临时表的语句执行得较慢,事务没有在短时间内完成,查询 PT_QueryPlan表的语句
才由于等待而被暂时挂起了,这与SQL Server的机制有关,Oracle不会默认事务隔离级别不会出现这
种问题!
    问题找到了,解决办法是select cguid code,cName name,cOften from PT_QueryPlan......执行
时不要对表加共享锁,语句改为select cguid code,cName name,cOften from PT_QueryPlan with
(nolock) ......,也就是在表名后加上with (nolock),简单吧!
   以下是根据网上的文章整理而成,供参考:
   在SQL Server 2005数据库查询时,为了提高查询的性能,我们往往会在表后面加一个with(nolock),让数据库在
查询时不锁定表,从而提高查询的速度。
并发访问:同一时间有多个用户访问同一资源,并发用户中如果有用户对资源做了修改,此时就会对其它用户产生
某些不利的影响,例如:
1:脏读:一个用户对一个资源做了修改,此时另外一个用户正好读取了这条被修改的记录,然后,第一个用户放
弃修改,数据回到修改之前,这两个不同的结果就是脏读。
2:不可重复读:一个用户的一个操作是一个事务,这个事务分两次读取同一条记录,如果第一次读取后,有另外
用户修改了这个数据,然后第二次读取的数据正好是其它用户修改的数据,这样造成两次读取的记录不同,如果事务中
锁定这条记录就可以避免。
3:幻读:指用户读取一批记录的情况,用户两次查询同一条件的一批记录,第一次查询后,有其它用户对这批数据
做了修改,方法可能是修改,删除,新增,第二次查询时,会发现第一次查询的记录条目有的不在第二次查询结果中,或
者是第二次查询的条目不在第一次查询的内容中。
   
为了避免并发访问产生的不利影响,SQL Server有两种并发访问的控制机制:锁、行版本控制,表后面加nolock是解
决并发访问的方案之一。
    从数据库系统的角度来看:分为独占锁(即排它锁),共享锁和更新锁。
1:共享 (S) :用于不更改或不更新数据的操作(只读操作),一般常见的例如select语句。
2:更新 (U) :用于可更新的资源中。防止当多个会话在读取、锁定以及随后可能进行的资源更新时发生常见形式的死锁。
3:排它 (X) :用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。确保不会同时同一资源进行多重更新。
隔离级别的分类:
1:未提交读,隔离事务的最低级别,只能保证不读取物理上损坏的数据;
2:已提交读,数据库引擎的默认级;
3:可重复读;
4:可序列化;隔离事务的最高级别,事务之间完全隔离。
小结:NOLOCK 语句执行时不发出共享锁,允许脏读 ,等于READ UNCOMMITTED事务隔离级别 。NOLOCK确实在查询时能提高
速度,但它并不是没有缺点的,起码它会引起脏读(读取其它事务尚未提交的数据)。这一点相当重要!能不能在应用中降低
锁的级别要视情况而定!!切记,切记
   
nolock的使用场景:
1:数据量特别大的表,牺牲数据安全性来提升性能是可以考虑的;
2:允许出现脏读现象的业务逻辑,反之一些数据完整性要求比较严格的场景就不合适了。
3:数据不经常修改的表,这样会省去锁定表的时间来大大加快查询速度。
综上所述,如果在项目中的每个查询的表后面都加nolock,这种做法并不科学,起码特别费时间,不如行版本控制来的直接有效。
而且会存在不可预期的技术问题。应该有选择性的挑选最适合的表来放弃共享锁的使用。

文章author:DBA,wanghengfeng老师



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值