首页 / 软件开发 / .NET编程技术 / 在查询中的每个表后面都加一个nolock是否合适?
在查询中的每个表后面都加一个nolock是否合适?2011-06-06 博客园 姜敏背景:目前参与的一个项目,我发现一个问题,就是大家在写查询时,为了性能 ,往往会在表后面加一个nolock,或者是with(nolock),其目的就是查询是不锁定 表,从而达到提高查询速度的目的。这点可能很多朋友在做开发时都会遇到,不 过如果说系统中的每个查询语句中的表都加上nolock,您是否同意这么做呢?在 回答这个问题前我先说下几个问题:什么是并发访问:同一时间有多个用户访问同一资源,并发用户中如果有用户 对资源做了修改,此时就会对其它用户产生某些不利的影响,例如:1:脏读,一个用户对一个资源做了修改,此时另外一个用户正好读取了这条 被修改的记录,然后,第一个用户放弃修改,数据回到修改之前,这两个不同的 结果就是脏读。2:不可重复读,一个用户的一个操作是一个事务,这个事务分两次读取同一 条记录,如果第一次读取后,有另外用户修改了这个数据,然后第二次读取的数 据正好是其它用户修改的数据,这样造成两次读取的记录不同,如果事务中锁定 这条记录就可以避免。3:幻读,指用户读取一批记录的情况,用户两次查询同一条件的一批记录, 第一次查询后,有其它用户对这批数据做了修改,方法可能是修改,删除,新增 ,第二次查询时,会发现第一次查询的记录条目有的不在第二次查询结果中,或 者是第二次查询的条目不在第一次查询的内容中。为什么会在查询的表后面加nolock标识?为了避免并发访问产生的不利影响 ,SQL Server有两种并发访问的控制机制:锁、行版本控制,表后面加nolock是 解决并发访问的方案之一。1> 锁,每个事务对所依赖的资源会请求不同类型的锁,它可以阻止其他事 务以某种可能会导致事务请求锁出错的方式修改资源。当事务不再依赖锁定的资 源时,锁将被释放。锁的类型:1:表类型:锁定整个表;2:行类型:锁定某个行;3:文件类型: 锁定某个数据库文件;4:数据库类型:锁定整个数据库;5:页类型:锁定8K为单 位的数据库页。锁的分类还有一种分法,就是按用户和数据库对象来分:1). 从数据库系统的角度来看:分为独占锁(即排它锁),共享锁和更新锁1:共享 (S) :用于不更改或不更新数据的操作(只读操作),一般常见的例 如select语句。2:更新 (U) :用于可更新的资源中。防止当多个会话在读取、锁定以及随后 可能进行的资源更新时发生常见形式的死锁。3:排它 (X) :用于数据修改操作,例如 INSERT、UPDATE 或 DELETE。确保 不会同时同一资源进行多重更新。2). 从程序员的角度看:分为乐观锁和悲观锁。1:乐观锁:完全依靠数据库来管理锁的工作。2:悲观锁:程序员自己管理数据或对象上的锁处理。一般程序员一看到什么锁之类,觉的特别复杂,对专业的DBA当然是入门级知 识了。可喜的是程序员不用去设置,控制这些锁,SQLServer通过设置事务的隔离 级别自动管理锁的设置和控制。锁管理器通过查询分析器分析待执行的sql语句 ,来判断语句将会访问哪些资源,进行什么操作,然后结合设定的隔离级别自动 分配管理需要用到的锁。2>:行版本控制:当启用了基于行版本控制的隔离级别时,数据库引擎 将 维护修改的每一行的版本。应用程序可以指定事务使用行版本查看事务或查询开 始时存在的数据,而不是使用锁保护所有读取。通过使用行版本控制,读取操作 阻止其他事务的可能性将大大降低。也就是相当于针对所有的表在查询时都会加 上nolock,同样会产生脏读的现象,但差别在于在一个统一管理的地方。说到了 基于行版本控制的隔离级别,这里有必要说下隔离级别的概念。隔离级别的用处:控制锁的应用,即什么场景应用什么样的锁机制。最终目的:解决并发处理带来的种种问题。