web-dev-qa-db-ja.com

UPDLOCK、HOLDLOCKについて混乱しています

テーブルヒント の使用を調査しているときに、次の2つの質問に出会いました。

両方の質問に対する答えは、(UPDLOCK, HOLDLOCK)を使用すると、他のプロセスはそのテーブルのデータを読み取ることができないと言いますが、私はこれを見ませんでした。テストするために、テーブルを作成し、2つのSSMSウィンドウを起動しました。最初のウィンドウから、さまざまなテーブルヒントを使用してテーブルから選択したトランザクションを実行しました。トランザクションの実行中に、2番目のウィンドウからさまざまなステートメントを実行して、ブロックされるものを確認しました。

テストテーブル:

CREATE TABLE [dbo].[Test](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Value] [nvarchar](50) NULL,
 CONSTRAINT [PK_Test] 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]

SSMSウィンドウ1から:

BEGIN TRANSACTION

SELECT * FROM dbo.Test WITH (UPDLOCK, HOLDLOCK)
WAITFOR DELAY '00:00:10'

COMMIT TRANSACTION

SSMS Window 2から(次のいずれかを実行):

SELECT * FROM dbo.Test
INSERT dbo.Test(Value) VALUES ('bar')
UPDATE dbo.Test SET Value = 'baz' WHERE Value = 'bar'
DELETE dbo.Test WHERE Value= 'baz'

ウィンドウ2で実行されるステートメントに対するさまざまなテーブルヒントの影響:

           (UPDLOCK)       (HOLDLOCK)    (UPDLOCK, HOLDLOCK)    (TABLOCKX)
---------------------------------------------------------------------------
SELECT    not blocked      not blocked       not blocked         blocked
INSERT    not blocked        blocked           blocked           blocked
UPDATE      blocked          blocked           blocked           blocked
DELETE      blocked          blocked           blocked           blocked

これらの質問で与えられた答えを誤解したか、テストで間違いを犯しましたか?そうでない場合、なぜ(UPDLOCK, HOLDLOCK)(HOLDLOCK)を単独で使用するのですか?


私が達成しようとしていることのさらなる説明:

テーブルから行を選択し、処理中にそのテーブルのデータが変更されないようにします。私はそのデータを変更していません。読み取りを許可したいと思います。

この回答 は、(UPDLOCK, HOLDLOCK)が読み取りをブロックすることを明確に示しています(私が望むものではありません)。 この回答 に関するコメントは、読み取りを妨げるのはHOLDLOCKであることを意味します。テーブルヒントの効果をよりよく理解し、UPDLOCKだけで目的の結果が得られるかどうかを確認するために、上記の実験を行い、それらの答えと矛盾する結果を得ました。

現在、私は(HOLDLOCK)を使用すべきだと考えていますが、間違いを犯したり、将来私に噛み付くであろう何かを見落としたことがあるのではないかと心配しています。

78
Jeff Ogata

UPDLOCKブロックが選択するのはなぜですか? ロック互換性マトリックス は、S/UおよびU/Sの競合に対して、競合なしのようにNを明確に示します。

HOLDLOCK ヒントについては、ドキュメントに次のように記載されています。

HOLDLOCK:SERIALIZABLEと同等です。詳細については、このトピックで後述するSERIALIZABLEを参照してください。

...

SERIALIZABLE:...スキャンは、SERIALIZABLE分離レベルで実行されているトランザクションと同じセマンティクスで実行されます...

トランザクション分離レベル トピックは、シリアライズ可能の意味を説明しています。

他のトランザクションは、現在のトランザクションが完了するまで、現在のトランザクションによって読み取られたデータを変更できません。

他のトランザクションは、現在のトランザクションが完了するまで、現在のトランザクション内のステートメントによって読み取られたキーの範囲に入るキー値を持つ新しい行を挿入できません。

したがって、表示される動作は製品ドキュメントで完全に説明されています。

  • UPDLOCKは、同時のSELECTもINSERTもブロックしませんが、T1によって選択された行のUPDATEまたはDELETEをブロックします
  • HOLDLOCKはSERALIZABLEを意味し、したがってSELECTSを許可しますが、T1によって選択された行の更新と削除をブロックします、as /テーブル、したがってanyinsert)。
  • (UPDLOCK、HOLDLOCK):実験では、上記のケースに加えてブロックするもの、つまりT2のUPDLOCKを持つ別のトランザクションを表示しません。
    SELECT * FROM dbo.Test WITH (UPDLOCK) WHERE ...
  • TABLOCKXは説明不要

本当の質問は何を達成しようとしているですか?ロックセマンティクスの完全な110%の理解なしでロックヒントを操作することは、トラブルを招いています...

OP編集後:

テーブルから行を選択し、処理中にそのテーブルのデータが変更されないようにします。

より高いトランザクション分離レベルのいずれかを使用する必要があります。 REPEATABLE READは、読み取ったデータが変更されないようにします。 SERIALIZABLEは、読み取ったデータが変更されることを防ぎますand新しいデータは挿入されません。クエリヒントを使用するのではなく、トランザクション分離レベルを使用するのが適切なアプローチです。 Kendra Littleには 分離レベルを説明する素敵なポスター があります。

93
Remus Rusanu

UPDLOCKは、将来の更新ステートメントの選択ステートメント中に1つまたは複数の行をロックする場合に使用されます。将来の更新は、トランザクションの次のステートメントになる可能性があります。

他のセッションは引き続きデータを表示できます。 UPDLOCKやHOLDLOCKと互換性のないロックを取得することはできません。

ロックした行を他のセッションが変更しないようにするには、UPDLOCKを使用します。ロックされた行を更新または削除する機能が制限されます。

他のセッションが表示中のデータを変更しないようにしたい場合は、HOLDLOCKを使用します。ロックした行を挿入、更新、または削除する機能が制限されます。これにより、クエリを再度実行し、同じ結果を確認できます。

20
Scott Bruns