我对bol短语感到困惑:

“无法为通过插入,更新或删除操作修改的表指定READUNCOMMINT和NOLOCK。SQL SERVER查询优化器忽略了适用于更新或删除语句的目标表中的“从子句”中的ReadUncommitting和Nolock提示” [1] [1

例如,如果我写

--script 1) 
UPDATE Test SET Txt=(Select Txt from TEST WITH(NOLOCK) where ID=1) 
WHERE ID=1

它是没有错误(或警告)的,可能等同于

--script 2)
set transaction isolation level SERIALIZABLE;
begin tran
Declare @nvarm nvarchar(max);

Select @nvarm=Txt from Test where ID=1;
--Select @nvarm;
UPDATE Test  SET Txt=@nvarm  WHERE ID=1;
commit;

也没有错误或警告。
它等效吗?

该表是相同的,但从逻辑上讲,源表不是我可以重写的目标表1)用不同的源表作为另一个(物理)表:

--script 3)
select *
into testDup
from TEST;

GO;

UPDATE Test SET Txt=(SELECT Txt FROM TestDUP WITH(NOLOCK) where ID=1) 
    WHERE ID=1

为什么在另一个桌子上应该忽略诺洛克?
或者,如果是错误的话,请问
如何编写更新具有“适用于更新或删除语句的目标表的NOLOCK提示”,因为即使在1)和2)物理表是相同的,但从逻辑上讲是源(在选择)表和目标。 (在更新中)表是不同的。

如何编写一个更新语句,证明(nolock)被忽略了?
为什么要忽略它?它被忽略了吗?
或者,如果这是一个错误的问题,那就
为什么语法允许保证被忽略的提示?

再说一次,要么写下文档中写的陈述是不可能的(或者是吗?),要么我不理解“忽略”的感觉(忽略它的感觉是什么? ...

Update2:
答案表明,在Update语句的“来自BOL DOCS [1]所主张的内容的内容中,Nolock并未忽略(更新)。
好吧,这个问题的本质:
您能给我任何示例(上下文),在更新语句的条款中忽略了nolock是有道理的吗?

[ 1 ]
表提示(Transact-SQL)
SQL Server 2008 R2
http://msdn.microsoft.com/en-us/library/ms187373.aspx

有帮助吗?

解决方案

在您的任何示例中,更新或删除语句的从条款均不明显。您从子征中的子句中有,但这不是同一回事。

这是一个从条款中进行更新:

UPDATE t
SET Col = u.Val
FROM   /* <-- Start of FROM clause */
   Table t WITH (NOLOCK)
       inner join
   Table2 u
       on
          t.ID = u.ID
/* End of FROM clause */
WHERE
    u.Colx = 19

而且,正如文档所调用的那样 WITH (NOLOCK) 在这种情况下将被忽略。关于为什么要忽略它,允许这样做,一个猜测是这样的提示在 SELECT “同一”查询的版本,人们确实经常编写选择(以确保他们针对正确的行/列),然后替换 SELECT 条款与 UPDATE/SET 一对条款,可以使其余的查询不变。


根据评论/VGV8的“答案”更新:

您的示例更新仍然不在查看 更新语句的子句

以下工作正常,即使在另一个连接上打开tablockx():

UPDATE T  SET Txt= td.Txt
FROM TEST t inner join TESTDUP td  WITH (NOLOCK) on t.ID = td.ID
where t.ID = 1

其他提示

无需猜测。

Sybase和MS SQL Server使用内部的自动2PL资源锁定,但完全符合ISO/IEC/ANSI SQL标准。当您尝试理解所有可能的组合时,语法会变得愚蠢,因为某些子句与每个命令无关。

手册试图说的话,但并不是用简单的英语说的是:

  • 对于任何外部操作或交易中的单个查询,您都可以执行 SET ISOLATION LEVEL
  • 可以使用 UNCOMMITTED, NOLOCK, HOLDLOCK语法也是如此
  • 如果您在外部查询中有一个IL,或者在事务中有一个查询,但想在内部查询中使用其他IL,可以完成(在内部查询上使用不同的调节器)
  • 因此,您可以在IL3处执行一项交易,并有一个 SELECT 内部执行IL0或IL1

分别地:

  • 无论您认为您在做什么或想做什么,因为锁定是自动的,并且 ISOLATION LEVEL 3必需的 为了 UPDATESDELETES, ,其中 READ UNCOMMITTEDNOLOCK 请勿申请,也不能使用,如果您使用了它们,服务器将忽略它们

创建并填写了2个相同的表测试和测试DUP [1],在一个会话(SSM的窗口)中,我执行

--2)
begin tran
Select Txt from TestDUP  with(TABLOCKX) 
WHERE ID=1
--rollback

哪个封锁同一表上的另一个会话(SSMS窗口)的选择,例如:

 --3.1)
select * from TestDUP

但不是

 --3.2)
select * from TestDUP WITH(NOLOCK)

请注意,3.1)被阻止,但3.2)却没有。

但是,使用Select从TestDup中更新另一个表测试

--4)WITH(NOLOCK) is not honored until completing
-- (commit/roollback)-ing transaction 2)
UPDATE Test  SET Txt=
(Select Txt from TESTDUP WITH(NOLOCK)  where ID=1)
  WHERE ID=1;

被阻止了,因为在另一个源表上使用(nolock)在更新语句的子句中忽略了。

更新:

--4.1)WITH(NOLOCK) is honored 
-- in FROM clause of UPDATE statement 
UPDATE Test  SET Txt= td.Txt
FROM TESTDUP td  WITH (NOLOCK)
where test.ID = 1 

--4.2) Note that without NOLOCK this script is blocked
-- until first transaction 2) completes (rollbacks or commits)
UPDATE Test  SET Txt= td.Txt
FROM TESTDUP td  WITH (NOLOCK)
where test.ID = 1  

因此,现在这是有道理的,但是它与文档相矛盾,因为NOLOCK不忽略更新语句条款的Nolock,不是吗?

[ 1 ]
创建2个相同填充的表测试和测试DUP:

if object_id('Test') IS not NULL
drop table Test;

CREATE TABLE Test (
  ID int IDENTITY PRIMARY KEY,
  Txt nvarchar(max) NOT NULL
)
GO
-----------
INSERT INTO Test
SELECT REPLICATE(CONVERT(nvarchar(max), 
     CHAR(65+ABS(CHECKSUM(NEWID()))%26)),100000)
GO 10

--COPYING TEST into TESTDUP with creating of the latter
select *
into testDup
from TEST;
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top