Nolockを使用してSelectが更新されたデータのポーションを照会する理由を誰かが説明できますか?
-
16-10-2019 - |
質問
私はから答えを読んでいました ここ (StackoverFlowから、ここで尋ねるべきだと思います)
ノロックとは、ロックをまったく配置しないことを意味します。
クエリは、1回のクエリでの更新後の更新前および一部のデータの一部を返す場合があります。
Nolockがテーブルにロックを置かないことを理解しているので、他の人は同じ時間に照会できます。
それが示している答えと例から、データが更新されている間にデータを取得します。
なぜそれが起こるのですか?
通常の選択では、テーブルにロックを配置することを試みると仮定しているので、更新ステートメントが実行されると、行またはページにロックを配置します。次に、Selectステートメントを実行しようとすると、更新ステートメントロックがリリースされるまでロックを配置できません。
しかし、この場合、Selectステートメントはテーブルにロックをかけようとしないため、更新ステートメントがロックをリリースするのを待たずに実行できますか?
解決
それはまったく真実ではありません NOLOCK
ロックをまったく配置しないことを意味します。このヒントの下でのクエリは引き続き取られます Sch-S
ロックと(おそらく HOBT
ロック)。
下 read committed
分離レベルSQL Server(いつもの)行レベルを取得します S
データが読み取られるとすぐにロックしてリリースします。これらはと互換性がありません X
コミットされていないアップデートにロックが保持されているため、汚れた読み取りを防ぎます。
リンクされた答えの例 SELECT
修正された行に遭遇した場合、クエリはブロックされていないため、部分的な更新を読むことは非常に可能性があります。
デフォルトでも発生する可能性があります read committed
隔離レベルもa SELECT
「前」の値でいくつかの行を読み取り、他の行は「後」値で読み取ります。状況を設計するだけで必要です
- クエリの選択]を選択しますrowの値を読み取ります
R1
そして、それをリリースしますS
ロック - クエリの更新を更新します
R2
そして、X
ロック - クエリを選択]を選択します
R2
そしてブロックされています。 - クエリの更新を更新します
R1
そして、X
ロック。 - トランザクションコミットを更新するため、ロックをリリースし、選択を読み取ることができます
R2
このタイプの状況は、たとえば SELECT
と UPDATE
関心のある行を見つけるために異なるインデックスを使用しています。
例
CREATE TABLE T
(
X INT IDENTITY PRIMARY KEY,
Y AS -X UNIQUE,
Name varchar(10),
Filler char(4000) DEFAULT 'X'
)
INSERT INTO T (Name)
SELECT TOP 2500 'A'
FROM master..spt_values
1つのクエリウィンドウで実行されます
DECLARE @Sum int
SELECT 'SET @@ROWCOUNT' WHERE 1=0
WHILE (@@ROWCOUNT = 0)
SELECT @Sum = SUM(LEN(Name))
FROM T
WHERE Y IN (-1, -2500)
HAVING SUM(LEN(Name)) = 3
これは、無限のループで実行されます。別の実行で
UPDATE T
SET Name=CASE WHEN Name = 'A' THEN 'AA' ELSE 'A' END
これにより、他のクエリでループを停止する可能性があります(そうでない場合は再試行してください)。 A,AA
また AA,A
他のヒント
ヒント NOLOCK
トランザクション分離レベルに相当します READ UNCOMMITTED
, 、1つのテーブルアクセス方法の範囲に制限されています。
それはあなたの結果に非コミットされたものをどのRUにしますか? うーん、実際には問題です」そうではないこと. 。以下で説明します。
まあ(これは粗雑な単純化です、私は知っています)MSSQL(その「デフォルトの動作で)はロックエンジンです。つまり、ロックを使用して一貫した方法でデータを読み取り/書き込みます。この単純化された説明では、MSSQLは2種類のロックを使用しています。 共有ロック と 排他的ロック.
共有(s)ロックは、リソース(行、行のページ、さらにはテーブル全体)を読み取ることができるロックですが、書き込みを許可しません。したがって、トランザクションT1がR1行にSロックを配置すると、R1を読み取ろうとするすべてのトランザクションはその読み取りを取得しますが、Sロックが生きている間、誰もR1に書き込むことはできません。
排他的(x)ロックは、共有ロックの対応物です。リソースへの排他的なアクセスが可能になります - Xロックを取得したものを除いて、他のトランザクションを読み書きできません。上記の例では、T1がSロックではなく、R1のXロックを取得した場合、 T1以外の誰もそれを読み書きできません。
それがテリーです。分離レベルはロックを尊重し、それらの有病率と特性を尊重します。すべてを除く READ UNCOMMITTED
. 。単純に、読み取りに関するロックに *(ここであなたの好みの悪い口語を置く)を与えます - あなたはまだ別のトランザクションがXロックを取得した行を更新することはできません。それは単に言う: 「クエリプランに関連するすべてのものを読みます。ロックの内容を無視します。」そしてそれをします。