Sql server 为什么要同时使用NOLOCK和NOWAIT?

Sql server 为什么要同时使用NOLOCK和NOWAIT?,sql-server,tsql,Sql Server,Tsql,一位同事编写了一个使用提示“with(NOLOCK,NOWAIT)”的查询 e、 g 假设: NOLOCK说“不要担心任何级别的锁,现在就读取数据” NOWAIT说“不要等待,如果表被锁定,只会出错” 问题: 为什么两者同时使用?当然NOWAIT永远不会实现,因为NOLOCK意味着它无论如何都不会等待锁定 NOLOCK与READUNCOMMITTED相同,其中: 。。。其他事务设置的独占锁不会阻止当前事务 从读取锁定的数据中删除事务 基于这句话,我想说您是正确的,发出NOLOCK实际上意味

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

e、 g

假设:

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

NOWAIT说“不要等待,如果表被锁定,只会出错”

问题:

为什么两者同时使用?当然NOWAIT永远不会实现,因为NOLOCK意味着它无论如何都不会等待锁定

NOLOCK
READUNCOMMITTED
相同,其中:

。。。其他事务设置的独占锁不会阻止当前事务 从读取锁定的数据中删除事务

基于这句话,我想说您是正确的,发出
NOLOCK
实际上意味着任何数据锁都是不相关的,因此
NOWAIT
是多余的,因为查询不能被阻止

然而,文章接着说:

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

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

看看在这种不太可能的情况下,
NOWAIT
是否得到了尊重,这将是一件有趣的事情。然而,出于您的目的,我想它可能是多余的。

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

create table T (ID int not null)
begin transaction
alter table T add ID2 int not null
保持此窗口打开,打开另一个查询窗口并执行:

select * from T WITH (NOLOCK,NOWAIT)
尽管有
NOWAIT
提示,尽管有文档记录它在遇到任何锁时立即返回消息,但第二个查询将挂起,等待模式锁

阅读以下文档:

NOWAIT

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

请注意,这是关于锁,any

NOLOCK
(实际上是
READUNCOMMITTED
):

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

因此,
NOLOCK
确实需要等待一些锁。
将它们一起使用没有任何意义。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窗口1

BEGIN TRANSACTION

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

--ROLLBACK TRANSACTION
SSMS窗口2

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

你为什么不试着用一些测试数据看看会发生什么?!已经这样做了,它立即返回-即NOLOCK won-我的问题是“为什么一起使用它们?是否存在NOLOCK不会赢的情况?”我想你是对的,
nowait
是多余的,但希望有人能以某种权威回答!刚刚做了测试
NOWAIT
仍然会阻止等待模式锁定,因此它看起来毕竟是多余的。@Damien\u不相信者-它甚至无法编译查询并开始执行,因此提示永远不会真正进入其中<代码>设置锁定超时0;使用(NOLOCK)从T中选择*将是完成此操作的唯一方法。
SELECT * FROM tempbackup.dbo.TEST_TABLE WITH(NOWAIT)
--SELECT * FROM tempbackup.dbo.TEST_TABLE WITH(NOLOCK,NOWAIT)