私は UPDATE 操作のロックを真剣に理解したことがありませんでしたが、最近 MSDN フォーラム でヒープ テーブルの更新のデッドロックの問題についての質問を目にしました。次のようなテーブルとデータです:
CREATE TABLE dbo.tb( c1 int, c2 char(10), c3 varchar(10) ); GO DECLARE @id int; SET @id = 0; WHILE @id <5 BEGIN; SET @id = @id + 1; INSERT dbo.tb VALUES( @id, 'b' + RIGHT(10000 + @id, 4), 'c' + RIGHT(100000 + @id, 4) ); END;
クエリ 1 で更新操作を実行します:
BEGIN TRAN UPDATE dbo.tb SET c2 = 'xx' WHERE c1 = 2; WAITFOR DELAY '00:00:30'; UPDATE dbo.tb SET c2 = 'xx' WHERE c1 = 5; ROLLBACK;
クエリ 1 の実行が開始したら、すぐに次の操作を実行します。クエリ 2 で
BEGIN TRAN UPDATE dbo.tb SET c2 = 'xx' WHERE c1 = 1; ROLLBACK;
なぜデッドロックが発生するのでしょうか? 条件を c1 = 4 に変更すると、デッドロックは発生しません。
デッドロックのパフォーマンスは、循環待機を形成することだと最初は思っていました (2 つのクエリの場合、ロックされたリソースがお互いに解放されるのを単に待っていると考えることができます)。
この例では、最初のクエリは 2 回更新され、最初にレコードを更新してロックし、その後 2 回目の更新を待ちますが、2 番目のクエリは 1 つのレコードのみを更新し、更新とロックを行います。レコードをロックします。クエリが競合しているため、ロックを取得できません。この時点では何もロックされず、更新が完了するまで待つ必要があります。デッドロックは発生しないように思えますが、他の理由でデッドロックが発生する可能性がありますか?
私のコンピューターで簡単にテストしてみたところ、確かにデッドロックはないようです。
しかし、後でプロファイルを通じて更新操作のロック状況を追跡したときに、私の分析が完全に間違っていたことに気づきました。主な理由は、更新操作でロックがどのように使用されるかが正しく理解されていないことです。
更新された U (更新ロック) と /msdn.microsoft.com/zh-cn/library/ms175519(v=sql.105).aspx に関する説明ですが、それは本当に曖昧です。 S ロックについても言及しています。S ロックは、条件を満たすレコードが見つかった後、X ロックに変換される処理で使用されるとずっと思っていました。アップデート用に。 プロフィール (プロファイラー) 追跡の結果から、これは間違った理解であったことがわかりました。プロフィールで新しい追跡を作成し、ロックでロックを選択します:取得(ロックを追加) 、Lock: Acquired (ロックを解除) 2 つのイベントを解決し、テスト用のクエリ ウィンドウに対応する spid のみを追跡するようにフィルターに設定します (PRINT を実行できます) @@ SPID が取得されます)、UPDATE dbo.tb SET c2 = などの更新ステートメントを実行します「xx」 WHERE c1 = 3 プロファイルで、条件を満たさないレコードに対して U ロック操作があることがわかります。条件を満たすレコードについては、最終的に X ロックに変換されます。以下に示すように。
この追跡結果にはSロックが存在しないことに注意してください。 さらに、いくつかのテストを行うことも学びました: 更新テストのレコード数を増やすと、データ スキャンに含まれるレコードに U ロックがあることがわかります。 、更新レコードに限定されません。これは、別の観点から見ると、大型時計ではスキャンがひどいことを示しています。 インデックス スキャンを使用する場合、スキャン対象のインデックス リソースに U ロックがあることも追跡を通じてわかります。更新にインデックスの変更が含まれない場合、対応するレコードのみが U から X へのロックを持ちます。 、インデックスの U ロックは解放されます。インデックスが影響を受ける場合、インデックスの U ロックは X ロックに変換されます。 削除操作は更新操作と似ています UPDATE aSET c2 = 'xx' FROM dbo.を使用しますTB AS a WITH( NOLOCK) WHERE c1 = 3 ロックの状況は同じで、U または 最後に、例に戻ってデッドロックの問題を調べてみましょう :
ここで説明する順序はデータの読み取り順序であり、ディスク上のレコードの順序は必ずしも INSERT レコードの順序と同じではないことに注意してください。同じ条件でテストしていないのですが、デッドロックの原因(私の環境ではたまたま読み込みの順番とINSERTの順番が違っていました) 大量のデータが関係する場合、更新時に、レコードの読み取り順序は、プロファイルによって追跡されるLock:Acquired (Lock) イベントを通じて確認できます。サーバーはそれをサポートしています。同時読み取りも行われます。これは、デッドロックを分析するときに考慮すべき要素でもあります この記事では、更新ロック (U) と排他ロック (X) の関連知識について説明します さらに関連するコンテンツについては、PHP 中国語 Web サイトに注目してください。 関連する推奨事項: SQL Server 2008 の実行プランで暗黙的なデータ型変換を処理するための機能強化 MySQL で 1 つの文で無限レベルの親子関係クエリを実装する方法 進捗状況 SQL Server FileStream にアクセスする方法
クエリ 1 では、最初の更新でテーブル内のすべてのレコードが順番にスキャンされ、更新条件を満たしているかどうかが判断されます。条件を満たしていない場合は X ロックが変換されます。合った場合は、U ロックを解除します。最初の更新が完了すると、クエリ 1 はレコードをロックし (トランザクションが完了していないためロックは維持されます)、2 番目の更新を待ちます
以上が更新ロック(U)と排他ロック(X)の関連知識を説明します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。