为什么“在应用于 UPDATE 或 DELETE 语句的目标表的 FROM 子句中”忽略 NOLOCK?
我对 BOL 短语感到困惑:
“不能为通过插入、更新或删除操作修改的表指定 READUNCOMMITTED 和 NOLOCK。SQL Server 查询优化器会忽略适用于 UPDATE 或 DELETE 语句的目标表的 FROM 子句中的 READUNCOMMITTED 和 NOLOCK 提示” [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;
运行时没有错误或警告。
是等价的吗?
表是相同的,但在 FROM 中,逻辑上它是源表而不是目标表 我可以用不同的源表重写 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?
或者,如果错了,请提问
如何编写具有“FROM 子句中适用于 UPDATE 或 DELETE 语句的目标表的 NOLOCK 提示”的 UPDATE,因为即使在 1) 和 2) 中,物理表也是相同的,但逻辑上是源(在 SELECT 中)表和目标(在更新中)表是不同的。
如何编写一条 UPDATE 语句来证明WITH(NOLOCK) 被忽略?
为什么要完全忽略它呢?被忽略了吗?
或者,如果这是一个错误的问题,那么
为什么语法允许保证被忽略的提示?
再说一次,要么不可能(或者是?)写出文档中写的这样的语句,要么我不理解“忽略”的含义(忽略它是什么意思?或者根本拥有它?) ...
更新2:
答案表明,在 UPDATE 语句的 FROM 子句中,NOLOCK 并未(更新)被忽略,这是 BOL 文档 [1] 所断言的。
好吧,这个问题的本质是:
你能给我任何例子(上下文),其中忽略 UPDATE 语句的 FROM 子句中的 NOLOCK 是有意义的吗?
[ 1 ]
表提示 (Transact-SQL)
SQL Server 2008 R2
http://msdn.microsoft.com/en-us/library/ms187373.aspx
I am confused by the BOL phrase:
"READUNCOMMITTED and NOLOCK cannot be specified for tables modified by insert, update, or delete operations. The SQL Server query optimizer ignores the READUNCOMMITTED and NOLOCK hints in the FROM clause that apply to the target table of an UPDATE or DELETE statement" [ 1 ]
For example, if I write
--script 1)
UPDATE Test SET Txt=(Select Txt from TEST WITH(NOLOCK) where ID=1)
WHERE ID=1
it is run without errors (or warnings) and is probably equivalent to
--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;
which is also run without errors or warnings.
Is it equivalent?
The table is the same but in FROM it is logically the source table not the target table
I could have re-written 1) with a different source table as another (physical) table:
--script 3)
select *
into testDup
from TEST;
GO;
UPDATE Test SET Txt=(SELECT Txt FROM TestDUP WITH(NOLOCK) where ID=1)
WHERE ID=1
Why should NOLOCK be ignored on another table?
Or, if it is wrong, question then
How to write UPDATE having "NOLOCK hints in the FROM clause that apply to the target table of an UPDATE or DELETE statement" because even in 1) and 2) the physical table is the same but logically the source (in SELECT) table and target (in UPDATE) table are different ones.
How to write an UPDATE statement demonstrating that WITH(NOLOCK) is ignored?
Why should it be ignored at all? Is it ignored?
Or, if it is a wrong question, then
Why does syntax permit the hint which is guaranteed to be ignored?
Once again, either it is impossible (or is it?) to write such a statement as written in documentation or I do not understand the sense of "ignores" (What is the sense to ignore it? or to have it at all?)...
UPDATE2:
The answers show that NOLOCK is NOT (updated) ignored in the FROM clause of UPDATE statement what is asserted by BOL docs [ 1 ].
Well, the essence of this question:
Can you give me any example (context) where ignoring of NOLOCK in FROM clause of UPDATE statement would have made sense?
[ 1 ]
Table Hints (Transact-SQL)
SQL Server 2008 R2
http://msdn.microsoft.com/en-us/library/ms187373.aspx
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
无需猜测。
Sybase 和 MS SQL 服务器使用内部自动 2PL 资源锁定,但完全符合 ISO/IEC/ANSI SQL 标准。当您尝试理解所有可能的组合时,语法会变得很愚蠢,因为某些子句并不与每个命令相关。
该手册试图表达的内容(但不是用简单的英语表达)是:
SET ISOLATION LEVEL
UNCOMMITTED、NOLOCK、HOLDLOCK
语法指定,以及分别在 IL0 或 IL1 上执行:
UPDATES
和DELETES
需要隔离级别 3,其中READ UNCOMMITTED
和NOLOCK
不适用,并且不能使用,如果您使用了它们,服务器将忽略它们No guessing required.
Sybase and MS SQL server use an internal, automatic 2PL resource locking, but with full compliance with the ISO/IEC/ANSI SQL Standard. The syntax gets silly when you try to understand all possible combinations, because some clauses are not relevant for every command.
What the manual is trying to say, but does not say in simple English, is:
SET ISOLATION LEVEL
UNCOMMITTED, NOLOCK, HOLDLOCK
syntax as wellSELECT
within it executing at IL0 or IL1Separately:
ISOLATION LEVEL 3
is required forUPDATES
andDELETES
, whereinREAD UNCOMMITTED
andNOLOCK
do not apply, and cannot be used, if you have used them the server will ignore themUPDATE 或 DELETE 语句的 FROM 子句在您的任何示例中都不明显。子查询中有 from 子句,但它们不是同一回事。
这是 UPDATE 的 FROM 子句:
并且,正如文档中所指出的,在这种情况下,
WITH (NOLOCK)
将被忽略。至于为什么允许这样做(如果要忽略的话),一种猜测是这样的提示在“相同”查询的 SELECT 版本中是有效的,并且人们确实经常编写 SELECT(以确保它们瞄准正确的行/列),然后将SELECT
子句替换为UPDATE
/SET
子句对,并且可以查询的其余部分保持不变。根据 vgv8 的评论/“答案”进行更新:
您的示例更新仍然没有查看 UPDATE 语句的 FROM 子句
即使在另一个连接上打开 TABLOCKX(),以下工作正常:
The FROM clause of an UPDATE or DELETE statement isn't evident in any of your examples. You have from clauses in subqueries, but those aren't the same thing.
Here's a FROM clause for an UPDATE:
And, as the documentation calls out, the
WITH (NOLOCK)
will be ignored in this case. As to why this is allowed if it's going to be ignored, one guess would be that such a hint would be valid in theSELECT
version of the "same" query, and people do frequently write SELECTs (to ensure they're targetting the correct rows/columns), and then replace theSELECT
clause with aUPDATE
/SET
pair of clauses, and can leave the rest of the query unaltered.Updated based on comment/"answer" from vgv8:
Your example update still isn't looking at the FROM clause of the UPDATE statement
The following works fine, even with the TABLOCKX() open on the other connection:
创建并填充 2 个相同的表 Test 和 TestDUP [1] 后,在一个会话(SSMS 窗口)中,我执行
阻止来自同一表上的另一个会话(SSMS 窗口)的 SELECT,例如:
但不注意
3.1)被阻止但 3.2) 则不然。
但是,使用 TestDUP 中的 SELECT 更新另一个表 TEST会被阻止,因为 UPDATE 语句的 FROM 子句中忽略另一个源表上的WITH(NOLOCK)。更新:
所以,它现在是有道理的,但它与文档相矛盾,因为 UPDATE 语句的 FROM 子句中的 NOLOCK 不会被忽略,不是吗?
[ 1 ]
创建 2 个填充相同的表 Test 和 testDUP:
Having created and filled 2 identical tables Test and TestDUP [ 1 ], in one session (windows of SSMS) I execute
which blocks SELECT from another session (SSMS window) on the same table, for example:
but not
Note that 3.1) is blocked but 3.2) is not.
Though, updating on another table TEST using SELECT from TestDUPis blocked because WITH(NOLOCK), on another source table, is ignored in FROM clause of UPDATE statement.Update:
So, it now makes sense but it contradicts to documentation since NOLOCK in FROM clause of UPDATE statement is NOT ignored, does not it?
[ 1 ]
Create 2 identically filled tables Test and testDUP: