0

私はBOLフレーズに混乱しています:

「挿入、更新、または削除操作によって変更されたテーブルには、READUNCOMMITTEDおよびNOLOCKを指定できません。SQLServerクエリオプティマイザは、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では、論理的にはソーステーブルであり、別の(物理)テーブルとは異なるソーステーブルで書き直した可能性のあるターゲットテーブルではありません。

--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)でも物理テーブルは同じですが論理的には、「UPDATEまたはDELETEステートメントのターゲットテーブルに適用されるFROM句のNOLOCKヒント」を含むUPDATEの記述方法を質問します。ソース(SELECT内)テーブルとターゲット(UPDATE内)テーブルは異なります。

WITH(NOLOCK)が無視されることを示すUPDATEステートメントを作成するにはどうすればよいですか?
なぜそれをまったく無視する必要があるのですか?無視されますか?
または、それが間違った質問である場合、
なぜ構文は無視されることが保証されているヒントを許可するのですか?

繰り返しになりますが、ドキュメンテーションに書かれているようなステートメントを書くことは不可能(またはそうですか?)であるか、「無視する」という意味がわかりません(無視するという意味は何ですか?またはまったく持つという意味ですか?) ..。。

UPDATE2:
回答は、BOLドキュメント[1]によってアサートされたUPDATEステートメントのFROM句でNOLOCKが無視されない(更新されない)ことを示しています。
さて、この質問の本質:
UPDATEステートメントのFROM句でNOLOCKを無視することが理にかなっている例(コンテキスト)を教えてください。

[1]
テーブルのヒント(Transact-SQL)
SQL Server 2008 R2
http://msdn.microsoft.com/en-us/library/ms187373.aspx

4

3 に答える 3

4

推測は必要ありません。

SybaseおよびMSSQLサーバーは、内部の自動2PLリソースロックを使用しますが、ISO / IEC /ANSISQL標準に完全に準拠しています。一部の句はすべてのコマンドに関連しないため、考えられるすべての組み合わせを理解しようとすると、構文がばかげてしまいます。

マニュアルが言おうとしているが、簡単な英語では述べていないのは、次のとおりです。

  • 外部操作、またはトランザクション内の単一のクエリに対して、実行しているものは何でも、次のことができます。SET ISOLATION LEVEL
  • UNCOMMITTED, NOLOCK, HOLDLOCK構文を使用して指定することもできます
  • 外部クエリに1つのILがある場合、またはトランザクション内に1つのクエリがあるが、内部クエリに別のILを使用したい場合は、実行できます(内部クエリで別のモジュレーターを使用します)
  • したがって、IL3でトランザクションを実行し、その中のトランザクションSELECTをIL0またはIL1で実行することができます。

別々に:

  • ロックは自動であり、andISOLATION LEVEL 3必要であるため、何をしている、または何をしたいのかに関わらず、andは適用されず、使用できません。これらを使用した場合、サーバーはそれらを無視します。UPDATESDELETESREAD UNCOMMITTEDNOLOCK
于 2011-01-17T23:10:11.820 に答える
2

UPDATEまたはDELETEステートメントのFROM句は、どの例でも明らかではありません。サブクエリにfrom句がありますが、それらは同じものではありません。

UPDATEのFROM句は次のとおりです。

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を記述します(正しい行をターゲットにしていることを確認するため) / columns)を選択し、SELECT句をUPDATE/句のペアに置き換えてSET、クエリの残りの部分を変更しないでおくことができます。


vgv8からのコメント/「回答」に基づいて更新:

あなたのサンプルアップデートはまだUPDATEステートメントのFROM句を見ていません

他の接続で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
于 2010-12-01T08:36:50.060 に答える
0

2つの同一のテーブルTestとTestDUP[1]を作成して入力した後、1つのセッション(SSMSのウィンドウ)で実行します

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

これは、同じテーブル上の別のセッション(SSMSウィンドウ)からのSELECTをブロックします。次に例を示します。

 --3.1)
select * from TestDUP

だがしかし

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

3.1)はブロックされますが、3.2)はブロックされないことに注意してください。

ただし、TestDUPのSELECTを使用して別のテーブルTESTを更新する

--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;

別のソーステーブルのWITH(NOLOCK)がUPDATEステートメントのFROM句で無視されるため、はブロックされます。

アップデート:

--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  

したがって、今では意味がありますが、UPDATEステートメントのFROM句のNOLOCKは無視されないため、ドキュメントと矛盾しますね。

[1]
同じように入力された2つのテーブルTestとtestDUPを作成します。

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;
于 2010-12-01T13:04:59.507 に答える