SQL Serverでは、読み取りロックはどのように機能しますか?


17

次の長時間実行クエリがあるとします

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

回答:


14

私はあなたが読んでお勧めしますSQL Serverがクエリを実行する方法の理解、それは読み、仕事とロックの仕組みを書き込む方法についての説明があります。

10000ftビューは次のとおりです。

  • 読み取り演算子は、データを読み取る前に、読み取りデータの共有ロックを取得します
  • 書き込み演算子は、データを変更する前に、変更するデータの排他ロックを取得します
  • データロックは単なる文字列です。データベースおよびオブジェクトによってスコープが設定されたキーのハッシュ。
  • ロック・マネージャはによると、すべての許可されたロックおよび検出の非互換性のリストを保持ロックの互換性マトリックス
  • 互換性のない要求は、それらをブロックする互換性のない許可が解放されるまで中断されます
  • 演算子はロック階層を使用して、より高いレベル(ページレベルまたはテーブルレベル、パーティションレベルオプションを無視)でデータを読み取りまたは更新する意図を宣言します。これにより、オペレーターは個々の行ごとにロックせずにテーブル全体をロックできます。
  • ロックの寿命と範囲ロックは、より高い分離レベルを実施するために使用されます

これは本当に氷山の一角にすぎません。主題は広大です。あなたの例では、多くの要因に依存するため、実際にロックされているものに関する質問に誰も答えることができません。もちろん、SELECT * FROM Table1 WHERE句がなく、を使用しているため、アプリケーションはを発行しないでください*。これらは、特にロック競合につながるため、悪い習慣です。

読み取りロックと書き込みロックが発生した場合は、行のバージョン管理とスナップショット分離を調べる必要があります。行のバージョン管理ベースの分離レベルについてをご覧ください。


テーブルのすべてのコンテンツが必要な場合(たとえば、14行しかない場合)SELECT * FROM Table1それがまさに私が必要とするものである場合、それはどのように悪い習慣ですか?
方位角

1
*テーブル構造が変更されると、アプリケーションが通常壊れる(結果に予期しない列が表示される)ため、それ自体は悪い習慣です。
レムスルサヌ

3

編集:@MaxVernonが指摘しているように、以下はNOLOCKを使用する提案ではありません。トランザクションレベルを設定することについて言及し、最初に立ち上げるREAD UNCOMMITEDよりも否定的な意味合いをそのままにしておくべきNOLOCKです。最初に投稿されたように:

迅速かつ簡単なのは、「はい、特定のインデックスヒントが指定されていない場合(NOLOCK、「ダーティリード」と呼ばれることもあります)または2番目のクエリのトランザクション分離レベルがREAD UNCOMMITED(まったく同じように動作する)に設定されていない限り、最初のクエリは2番目のクエリをブロックします、いいえ、違います。"

相互排他的であるかそうでない場合、WITH2番目の句を含めることを伴う質問で提供される追加の詳細に応じて、SELECT2つのクエリ間の相互作用はほぼ同じになります。

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;

他の(Intent-Exclusive)ロックと混同しないように、(排他的)モードでKEY挿入トランザクションを実行するspidによって型ロックが保持されているのが見えるはずです。ロックドキュメントはながらことを示すロックレンジ特有であり、それはまた、データを変更することによって影響を受けた列を挿入または更新し、他のトランザクションを防ぎ、その中にそれが元のクエリの範囲内に入ることができることを含んでいました。保持されているロック自体は排他的であるため、最初のクエリは他の同時トランザクションからリソースへのアクセスを妨げています。実際には、列のすべての行は、最初のクエリで指定された範囲内にあるかどうかに関係なくロックされます。 XIXKEY

Sロックは、このように第二のセッションであろう保持されるWAITまで、X別の予防、ロッククリアX(又はU第二セッションの存在を正当化し、その読み出し動作を完了する前に、異なる同時SPIDからそのリソース上で取られるの)ロックをSロックします。

ここで明確にするための編集:ここで言及されリスクの簡単な説明から汚れた読み取りが間違っている場合を除き... 編集3:asを書き込むバックグラウンドチェックポイントの影響を考慮していないことに気付きましたディスクへのまだコミットされていないトランザクションので、はい、私の説明は誤解を招くものでした。

2番目のクエリでは、最初のバッチはコミットされていないデータを返すことができます(この場合は)。デフォルトのトランザクション分離レベルで実行される2番目のバッチREAD COMMITEDは、最初のセッションでコミットまたはロールバックが完了した後にのみ戻ります。

ここから、クエリプランと関連するロックレベルを確認できますが、SQL Serverのロックに関するすべてをここで読むことができます


1
WITH (NOLOCK)この場合、使用に関する警告の言葉が役立ちます。詳細については、brentozar.com / archive / 2011/11 /…およびbrentozar.com/archive/2013/02/…を参照してください。
マックスヴァーノン14年

3
ああ、WITH (NOLOCK)ヒントはコミットされていないメモリからダーティページを返しません。ライターがテーブルで使用するページに行を更新または追加することをブロックせずに、実際にテーブルから行を読み取ります(ディスク上またはメモリ内キャッシュ)。
マックスヴァーノン14年

2
よくわかりません。「1番目のクエリが2番目のクエリの実行を妨げているか?」「いいえ」の場合、2番目の質問に対する答えはどのように「はい」になりますか?どの質問に答えているのかを明確にし、答えを広げることができますか?
すべての取引のジョン14

編集者の皆さん、ごめんなさい!他に不明な点がある場合はお知らせください!
Avarkx 14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.