次の長期実行クエリがあるとします
UPDATE [Table1]
SET [Col1] = 'some value'
WHERE [Col2] -- some clause which selects thousands of rows
上記のクエリの実行中に次のクエリが実行されたとします。
SELECT *
FROM [Table1]
最初のクエリは、最初のクエリが完了するまで2番目のクエリの実行を妨げますか?もしそうなら、最初のクエリは、2番目のクエリがすべての行、またはWHERE句に含まれる行だけで実行されるのを防ぎますか?
編集:
2番目のクエリが
SELECT [Col1], [Col2]
FROM [Table1]
WHERE [Col2] -- some clause whose matching elements overlap those from
-- the clause in the first query and which has additional matching elements
SQL Serverがクエリを実行する方法を理解する を読むことをお勧めします。これには、読み取りと書き込みがどのように機能し、ロックがどのように機能するかについての説明があります。
10000ftビューは次のようになります。
これはまさに氷山の一角です。主題は広大です。あなたの例では、多くの要因に依存するため、実際にロックされているものについての質問に誰も答えることはできません。もちろん、WHERE句がなく、SELECT * FROM Table1
を使用しているため、*
を発行するアプリケーションはありません。これらは、とりわけ、ロック競合を正確に引き起こすため、悪い習慣です。
読み取りロックと書き込みロックが発生した場合は、行のバージョン管理とスナップショットの分離を調べる必要があります。 行のバージョン管理に基づく分離レベルについて をお読みください。
編集: @ MaxVernon が指摘しているように、以下はNOLOCKを使用するための提案ではありません。トランザクションレベルをREAD UNCOMMITED
に設定することについて述べ、NOLOCK
を最初に立ち上げるよりも、否定的な意味合いをそこに置きます。最初に投稿されたとおり:
迅速かつ簡単です。「はい、特定のインデックスヒントが指定されていない限り、最初のクエリは2番目のクエリをブロックします( [〜#〜] nolock [〜#〜] 、「ダーティリード」と呼ばれることもあります)または、2番目のクエリのトランザクション分離レベルがREAD UNCOMMITED
(同じように動作する)に設定されている、いいえ、そうではありません。」
2番目のWITH
にSELECT
句を含めることを伴う質問で提供された追加の詳細に応じて、相互に排他的またはその他の方法で、2つのクエリ間の相互作用はほぼ同じになります。
IF NOT EXISTS ( SELECT 1
FROM sys.objects
WHERE name = 'Foo'
AND type = 'U' )
BEGIN
--DROP TABLE dbo.Foo;
CREATE TABLE dbo.Foo
(
Foo_PK BIGINT IDENTITY( 1, 1 ) NOT NULL,
PRIMARY KEY ( Foo_PK ),
Bar BIT,
x BIT,
y BIT,
z BIT
);
CREATE NONCLUSTERED INDEX IX_Foo_x
ON dbo.Foo ( x );
INSERT INTO dbo.Foo ( Bar, x, y, z )
VALUES ( 1, 1, 1, 1 ), ( 0, 0, 0, 0 );
END;
GO
BEGIN TRANSACTION;
UPDATE dbo.Foo
SET y = 0
WHERE x = 1;
-- COMMIT TRANSACTION;
別のセッションで、以下を実行します。
SELECT *
FROM dbo.Foo WITH ( NOLOCK );
GO
SELECT *
FROM dbo.Foo;
現在保持されているロックを調べるには、sp_lock
を、できればさらに別のセッションで実行します。
EXECUTE dbo.sp_lock;
KEY
タイプのロックがX
(排他的)モードで挿入トランザクションを実行するspidによって保持されていることを確認します。他のIX
(意図的排他的)と混同しないでください。 )ロック。 lock のドキュメントは、KEY
ロックが範囲固有である一方で、他のトランザクションが影響を受ける列を挿入または更新して、そこに含まれるデータを変更することにより、落下する可能性があることを示しています元のクエリのその範囲内。保持されているロック自体が排他的であるため、最初のクエリはanyの他の同時トランザクションからのリソースへのアクセスを妨げています。実際には、最初のクエリで指定された範囲内にあるかどうかに関係なく、列のすべての行がロックされます。
したがって、2番目のセッションによって保持されているS
ロックは、WAIT
ロックが解除されるまでX
になり、別のX
(またはU
)が防止されます2番目のセッションが読み取り操作を完了する前に、別の並行spidからそのリソースがロックされないようにし、S
ロックの存在を正当化します。
わかりやすくするために編集します。ダーティリードが ここで述べたリスク ...の簡単な説明にあると誤解しない限り、編集3:まだコミットされていないトランザクションをディスクに書き込むバックグラウンドチェックポイントの影響を考慮していないことに気付いたので、そうです、私の説明は誤解を招くものでした。
2番目のクエリでは、最初のバッチはコミットされていないデータを返すことができます(この場合、この場合)。 2番目のバッチは、デフォルトのトランザクション分離レベルREAD COMMITED
で実行され、最初のセッションでコミットまたはロールバックが完了した後にのみ戻ります。
ここから、クエリプランと関連するロックレベルを確認できますが、SQL Serverのロックに関するすべてを読むことができます here 。