SQL Server 中的 NOLOCK 到底是什么意思?

本文详细解释了SQL查询中使用NOLOCK提示的作用与原理。通过实际案例演示了NOLOCK如何避免查询阻塞,同时揭示了读取未提交数据的风险。适用于需要优化查询性能的数据库开发者。

http://blog.sina.com.cn/s/blog_7d3b18a50100rfwg.html

以前遇到过,但仅限于听同事说加上NOLOCK好一些,今天仔细研究测试了下,终于理解了,那么加与不加到底区别在哪呢?

    我先说下其区别,之后再做测试。

    大家都知道,每新建一个查询,都相当于创建一个会话,在不同的查询分析器里面进行的操作,可以影响到其他会话的查询,极端的情况可能会一直处于阻塞中,哪怕只是一个很简单的查询都“特别慢”。

    BEGIN TRAN 是开始一个事务的意思,开始之后可执行一些SQL语句,接着需要执行COMMIT进行提交或者ROLLBACK进行回滚,否则就会出现上面的情况。但如果使用NOLOCK进行查询的时候,就不会因为别的回话没有提交或回滚,而受阻塞。所以概括起来,可以用以下语句来总结:

    NOLOCK能使当前会话的查询,不受其它会话的事务所阻塞。但是这样做,就读取了其它事务的“修改后未提交的”数据。

    现在我们进行测试,一定要注意,必须在多个会话下才可以,也就是说,需要建三个查询分析器窗口。

    表用最简单的表,自己动手建一个。

    查询分析器一:执行

       SELECT * FROM dbo.test_main

       得到

        id    value
           one
           two
           three
           four

       接着执行如下:

       BEGIN TRAN
       INSERT INTO test_main VALUES(5, 'five')

       一行受影响   

    查询分析器二:执行

      SELECT * FROM dbo.test_main

      则卡死,受上一会话所阻塞。查不出结果。

      补充:那么卡死怎么办呢?我们已经说过,要执行提交或者回滚操作才可以,那么在会话一中执行COMMIT即可。 之后此查询立刻显示结果。

    查询分析器三:执行

       SELECT * FROM test_main(NOLOCK)

      则显示如下

       id    value
           one
           two
           three
           four

           five

       但最后一行并没有真正存储在数据库中,因为会话一还没有进行提交,我们用NOLOCK就查询出来了。

  也许你会想,那什么情况下用NOLOCK呢?经过我们的分析,用NOLOCK是为了避免出现卡死状态,那我们就可以分析其环境了。

  一个经常操作的表,并且每次操作都很重要,这样一般要用到事务进行处理,因为可以避免出错的几率,

我们查询时,要用NOLOCK,否则遇上卡死的几率很大。别人执行一个事务,还没处理完呢,你就查询了,那就卡死了。有了NOLOCK就可以解决这个问题了。

 

<think>我们正在讨论SQLServer中的NOLOCK提示。根据引用内容,NOLOCK提示用于指定查询在读取数据时不使用锁,从而避免被其他事务阻塞。但同时,它允许读取未提交的数据(脏读),以及可能出现不可重复读和幻读的问题。作用:1.避免阻塞:当查询使用NOLOCK时,它不会对读取的数据加共享锁,因此不会与正在修改数据的排他锁冲突。2.提高并发性:由于不加锁,其他事务可以同时修改数据,减少了等待。负面影响:1.脏读:可能读取到未提交的数据,这些数据可能随后被回滚。2.不可重复读:在同一事务中多次读取同一数据可能得到不同结果(因为其他事务可能修改了数据)。3.幻读:可能读取到其他事务插入的新行(幻行)或删除的行。使用场景:-在需要快速读取数据且对数据一致性要求不高的场景,如生成报表或分析历史数据。-在读取的数据不会被修改(如归档数据)或可以容忍少量不一致的情况下。注意事项:-在事务性操作(如银行交易)中避免使用,因为脏读可能导致严重问题。-在跨服务器查询时,不能使用WITH(NOLOCK)语法,但可以使用NOLOCK(不加WITH)。-SQLServer2005及更高版本的同义词只支持WITH(NOLOCK)语法。示例查询:```sql--使用NOLOCK提示SELECT*FROMSales.OrdersWITH(NOLOCK)WHERECustomerID=10;--等同于设置事务隔离级别为READUNCOMMITTEDSETTRANSACTIONISOLATIONLEVELREADUNCOMMITTED;SELECT*FROMSales.OrdersWHERECustomerID=10;```总结:NOLOCK提示是一种用数据一致性换取并发性能的机制,使用时需权衡利弊。§§相关问题§§1.NOLOCK提示和设置事务隔离级别为READUNCOMMITTED有何区别?2.在哪些情况下使用NOLOCK提示是安全的?3.如何避免NOLOCK提示带来的脏读问题?4.SQLServer中除了NOLOCK还有哪些表提示?</think>### SQL ServerNOLOCK 提示的作用及影响 #### **作用原理** NOLOCK 提示(或 `WITH (NOLOCK)`)用于查询时**跳过共享锁机制**,允许读取未提交的数据(脏读)。其核心行为包括: 1. **避免阻塞**:当其他事务持有排他锁(如更新数据时),使用 NOLOCK 的查询不会被阻塞,可直接读取数据[^1][^3]。 - 示例:事务 A 更新数据未提交时,事务 B 使用 NOLOCK 仍能读取到 A 修改中的临时值。 2. **隔离级别等效**:功能等同于将事务隔离级别设置为 `READ UNCOMMITTED`[^2]。 3. **不生成锁**:查询过程不申请共享锁,减少锁竞争。 #### **主要影响** | **优点** | **风险** | |-----------------------------|----------------------------------| | ✅ 提升查询并发性能 | ❌ **脏读**:读取未提交数据(可能回滚)[^2] | | ✅ 减少死锁概率 | ❌ **不可重复读**:同事务多次查询结果不一致 | | ✅ 适用高并发只读场景 | ❌ **幻读**:读取到其他事务新增/删除的行 | #### **使用场景** 1. **容忍数据延迟**:报表分析、历史数据查询等非实时场景。 2. **高并发只读操作**:如大屏监控、只读从库查询。 3. **紧急排查**:当生产环境锁阻塞严重时临时使用。 #### **语法差异** ```sql -- 标准写法(推荐) SELECT * FROM Orders WITH (NOLOCK) WHERE Status = 1; -- 旧式写法(跨服务器查询时部分版本支持) SELECT * FROM Orders (NOLOCK) WHERE Status = 1; ``` > 📌 注意:SQL Server 2005+ 的同义词仅支持 `WITH (NOLOCK)` 语法[^2]。 #### **注意事项** 1. **事务一致性**:禁止在资金交易、订单处理等需强一致性的场景使用。 2. **替代方案**:考虑 `READ COMMITTED SNAPSHOT` 隔离级别,通过行版本控制避免脏读。 3. **跨服务器查询**:链接服务器查询时需用 `NOLOCK`(不加 `WITH`)[^2]。 > ⚠️ **典型风险案例**: > 事务 A 更新金额(`UPDATE Accounts SET Balance=200 WHERE ID=1`),未提交时事务 B 用 NOLOCK 读到 `Balance=200`,但 A 发生错误回滚后实际余额仍为原值,导致 B 获得错误数据[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值