为什么一起使用NOLOCK和NOWAIT?

时间:2014-02-19 15:19:24

标签: sql-server tsql

一位同事写了一个使用提示“with(NOLOCK,NOWAIT)”的查询。

e.g。

select first_name, last_name, age
from people with (nolock,nowait)

假设:

NOLOCK说“不要担心任何级别的锁定,只需现在读取数据”

NOWAIT说“不要等,如果桌子被锁定就会出错”

问题:
为什么同时使用两者?当然NOWAIT永远不会实现,因为NOLOCK意味着它不会等待锁定......?

3 个答案:

答案 0 :(得分:5)

这是多余的(或至少是无效的)。在一个查询窗口中,执行:

create table T (ID int not null)
begin transaction
alter table T add ID2 int not null

打开此窗口,打开另一个查询窗口并执行:

select * from T WITH (NOLOCK,NOWAIT)

尽管有NOWAIT提示,尽管它被记录为在遇到任何锁定时立即返回消息,但第二个查询将挂起,等待Schema锁定。

<击> 阅读Table Hints上的文档:

NOWAIT

  

指示数据库引擎在表上遇到锁定时立即返回消息

请注意,这是关于锁定,任何锁定。

NOLOCK(嗯,实际上是READUNCOMMITTED):

  

READUNCOMMITTED和NOLOCK提示仅适用于数据锁。所有查询(包括具有READUNCOMMITTED和NOLOCK提示的查询)在编译和执行期间都会获取Sch-S(模式稳定性)锁。因此,当并发​​事务在表上持有Sch-M(模式修改)锁时,将阻止查询。

因此,NOLOCK确实需要等待某些锁定。

答案 1 :(得分:3)

NOLOCKREADUNCOMMITTED相同,MSDN states

  

...由其他交易设置的排他锁不阻止当前   读取锁定数据的交易。

根据该句子,我会说你是正确的,并且发布NOLOCK实际上意味着任何数据锁都无关紧要,因此NOWAIT是多余的,因为查询无法被阻止。

然而,文章接着说:

  

READUNCOMMITTED和NOLOCK提示仅适用于数据锁

您还可以获取架构修改锁,NOLOCK不能忽略这些锁。如果您在更新架构对象时使用NOLOCK发出了查询,则可能会被Sch-M类型的锁阻止您的查询。

有趣的是,在不太可能的情况下,NOWAIT是否真正受到尊重。但是出于你的目的,我猜它可能是多余的。

答案 2 :(得分:1)

将它们一起使用没有任何意义。 NOLOCK会覆盖NOWAIT 的行为。这是NOWAIT功能的演示。评论NOLOCK并观看记录返回,尽管有独家锁定。

创建表格。执行第一个SSMS窗口而不提交事务。由于没有等待,执行第二个窗口会出错。注释掉第一个查询并使用NOLOCK和NOWAIT执行第二个查询。得到结果。完成后回滚您的交易。

<强> DDL

USE [tempbackup]
GO

/****** Object:  Table [TEST_TABLE]    Script Date: 02/19/2014 09:14:00 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [TEST_TABLE](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](50) NULL,
 CONSTRAINT [PK_TEST_TABLE] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

INSERT INTO tempbackup.dbo.TEST_TABLE(Name) VALUES ('MATT')

GO

SSMS WINDOW 1

BEGIN TRANSACTION

UPDATE tempbackup.dbo.TEST_TABLE WITH(XLOCK) SET Name = 'RICHARD' WHERE ID = 1

--ROLLBACK TRANSACTION

SSMS WINDOW 2

SELECT * FROM tempbackup.dbo.TEST_TABLE WITH(NOWAIT)
--SELECT * FROM tempbackup.dbo.TEST_TABLE WITH(NOLOCK,NOWAIT)