2

スナップショット分離がこの問題を解決することはわかっていますが、オーバーヘッドを回避できるように、この特定のケースで NOLOCK が安全かどうか疑問に思っています。

次のようなテーブルがあります。

drop table Data

create table Data
(
    Id BIGINT NOT NULL,
    Date BIGINT NOT NULL,
    Value BIGINT,
    constraint Cx primary key (Date, Id)
)

create nonclustered index Ix on Data (Id, Date)

テーブルへの更新はありません。削除は発生する可能性がありますが、テーブルのもう一方の古い端に影響を与えるため、SELECT と競合することはありません。挿入は定期的であり、(Id, Date) インデックスへのページ分割は非常に一般的です。

標準の INSERT と SELECT の間に次のようなデッドロック状況があります。

select top 1 Date, Value from Data where Id = @p0 order by Date desc

INSERT は Cx (Date, Id; Value) の次に Ix (Id, Date) のロックを取得しますが、SELECT は Ix (Id, Date) と Cx (Date, Id; Value) のロックを取得するためです。これは、SELECT が最初に Ix をシークし、次に Cx のシークに参加するためです。

クラスター化インデックスと非クラスター化インデックスを交換すると、このサイクルが中断されますが、他の (より複雑な) SELECT とのサイクルが発生するため、受け入れられる解決策ではありません。

NOLOCK を SELECT に追加すると、この場合に問題が発生する可能性はありますか? 返品できますか:

  1. TOP 1を頼んだのに複数行?
  2. 行が存在し、コミットされているにもかかわらず、行がありませんか?
  3. 最悪なのは、WHERE 句を満たさない行ですか?

私はこれについてオンラインで多くのことを読みましたが、私が見た過大または過少の異常の唯一の再現 ( 1 つ2 つ) はスキャンを伴います。これには、シークのみが含まれます。Jeff AtwoodのNOLOCK の使用に関する投稿があり、良い議論が生まれました。Rick Townsend のコメントに特に興味を持ちました。

第 2 に、ダーティ データを読み取ると、まったく間違った行を読み取るリスクが生じます。たとえば、select が行を見つけるためにインデックスを読み取る場合、select が実際のデータ行を読み取るときに、更新によって行の場所が変更されます (たとえば、ページ分割またはクラスター化インデックスへの更新が原因で)。 、もう存在しないか、まったく別の行です!

これは、挿入のみで更新なしで可能ですか? もしそうなら、挿入専用テーブルでのシークでさえ危険である可能性があると思います。


アップデート:

スナップショット分離がどのように機能するかを理解しようとしています。トランザクションがテーブルを読み取り (共有ロックなしで!)、関心のある行を見つけて、tempdb のバージョン ストアから古いバージョンの行を取得する必要があるかどうかを確認する、行ベースのようです。

しかし、私の場合、複数のバージョンを持つ行はないため、バージョン ストアはかなり無意味に思えます。また、行が共有ロックなしで見つかった場合、NOLOCK を使用した場合とどう違うのでしょうか?

4

2 に答える 2

7

NOLOCK または READ UNCOMMITTED を使用すると、一貫性の保証が失われます。限目。

一貫性が必要な場合は、ダーティ リードを実行しないでください。あなたの説明全体は、将来のリリースで変更される可能性のある文書化されていない動作に依存しており、さらに悪いことに、クエリに期待する特定のアクセスプランに依存しています。クエリ オプティマイザーは、適切と思われるプランを自由に選択できます。また、本番環境では想定が崩れる可能性があります。振り出しに戻ります。結果に直面する準備ができていない場合は、ダーティ リードを実行しないでください。

これが当てはまるかどうかは不明であり、クエリ/テーブルで何を達成しようとしているのかは明確ではありませんが、おそらくこの記事が役立つかもしれません: Using tables as Queues .

更新
NOLOCK 読み取りが一貫性のない状態を読み取る場合 (たとえば、古い非クラスター化インデックス キーを読み取り、それをクラスター化インデックス内の欠落している行まで追跡する)、スナップショット読み取りはバージョン ストア内の「欠落」行を検出します。安定したデータの場合、スナップショット読み取りは nolock 読み取りと同じです。バージョン ストアの魔法は、データが変更されるたびに (コミットされていない更新) 有効になります。これは、スナップショットの読み取りがバージョン ストアに入り、「古い」値 (安定した一貫性のある値) が検出されるためです。ララランド。

于 2010-06-08T22:14:41.370 に答える
1

この場合、NOLOCK を使用すると安全です。もう 1 つの考え: Ix インデックスに含まれる列として Value を追加すると、Cx のシークがなくなるはずです。

create nonclustered index Ix on Data (Id, Date) include (Value)
于 2010-06-08T21:56:30.950 に答える