web-dev-qa-db-ja.com

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTEDの利点

私が一般的なSQLクエリの大部分で_SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED_を使用しているのは、主に最初に言語を学習したときにドリルダウンされたためです。

私の理解では、この分離レベルはWITH (NO LOCK)と同じように機能しますが、私は_SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED_のみを使用する傾向があります。

  • _SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED_よりもWITH (NO LOCK)を使用する必要がある時期はありますか?.
  • _SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED_は、他のユーザーが私が読んでいるテーブルからロックアウトされるのを防ぎますか?
  • _SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED_を使用してロックを停止したが、データを読み取っているだけの場合、それを使用する意味は何ですか?ロックを生成するのはシステム集中型クエリだけですか?たとえば5〜10秒で返されるクエリを実行するときに使用する価値はありますか?
  • おそらくダーティデータの更新を回避するために、更新で使用されるデータを読み取るときに_SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED_を使用しないように言われました。これが唯一の理由でしょうか?
  • 私が取り組んでいるデータベースのタイプには、本番環境とテスト環境があります。運用環境を照会することはほとんどありませんが、必要な場合は、通常、クエリで_SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED_を使用します。これでダーティリードが可能であることを理解しています。最終的にデータベースにコミットされない可能性のあるデータを受信すること(およびその結果、結果をスローすること)を除いて、他にどのようなタイプの「ダーティリード」が可能ですか?

大量の質問でごめんなさい。

12
dmoney

あなたがそれをそのように学んだことは恐ろしいことです(ごめんなさい!)。

_READ UNCOMMITTED_はい、すべての行を読みましょう。 INSERTUPDATEDELETE操作で現在使用されている人でもです。これは、ブロックが非常に有害なデータやミッションクリティカルなSELECT- Statementsをすばやく確認する必要がある場合に非常に役立ちます。

実際には、あなたはあなたの整合性を危険にさらします。削除または変更のために現在使用されている行を読み取る場合があります。また、誤った値を読み取ったように見える場合もあります。これはまれなことですが、発生する可能性があります。それはどういう意味ですか?さて、非常に広い行を考えてください(多くの長いnvarchar列を持つ多くの列があります)。この行で更新が行われ、新しい値が設定されます。まれなケースですが、半分の行しか読み取らないことがあります。たとえば、ユーザーがログイン値を変更すると、別のことが起こります。メール+パスワードを変更します。メールは既に設定されていますが、パスワードは設定されていません。この方法では、一貫性のない状態になります。

_READ UNCOMMITTED_を忘れることをお勧めします。 本当にが必要な場所で使用してください。

_READ_COMMITTED_SNAPSHOT_データベースオプションを有効にすることもできます。そのため、tempdbで行のバージョン管理が有効になっているため、_READ COMMITTED SNAPSHOT_を使用できます。この方法では、行の別の(古い)バージョンを読み取るだけです。これによってクエリがブロックされることはありません。しかし、古い値を読み取ることもあるかもしれませんが、一貫した古い値です。

別のアイデアは、WITH(READPAST)の代わりにWITH(NOLOCK)にすることもできます。 (_SNAPSHOT ISOLATION_のように)テーブルの古い状態を読み取りますが、代わりに現在ロックされているすべての行をスキップします。

26
Ionic

受け入れられた回答が示すように、誤ったデータを読み取るリスクがあるため、READ UNCOMMITTED分離レベル(本当に必要な場合を除いて)の使用を忘れてください。しかし、あなたの質問の3番目の箇条書きに答えるために、私が役立つと思う2つの状況があります。

  1. SQL Server SSISパッケージを作成してテストする場合、パッケージのステップがトランザクションにラップされる場合があります。 SSISデバッガーで段階的にパッケージを実行してパッケージをテストする場合は、テーブルがロックされているときにテーブルを調べることができます。 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTEDを使用すると、SQL Server Manager Studioを使用して、パッケージのデバッグ中にテーブルを調べることができます。

  2. SQL Server Manager Studioでは、T-SQLコードをトランザクションにラップしてテストし、変更をロールバックするオプションを提供できます。たとえば、テストデータベースでは、テストの一部としてデータを初期状態に復元することができます。トランザクションでラップされたコードをテストしていて、トランザクションの進行中にロックされたテーブルをチェックしたい場合は、SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTEDを使用して、別のウィンドウで値を調べることができます。

これらはREAD UNCOMMITTEDのかなりあいまいな使用法であることは認めますが、テスト環境で有用であることがわかりました。

2
Ubercoder

ほとんどのデータベースでは、挿入、削除、更新であっても、アクティビティの大部分は明示的なトランザクションの外にあります。

確かに、READ UNCOMMITTED(ダーティリード)はこれらの場合に誤った情報を提供する可能性がありますが、その情報は5秒前に正しかったです。

ダーティリードが本当に悪い結果を生成するのは、トランザクションが失敗してロールバックする必要があるとき、または明示的なトランザクションを使用して通常一緒に更新される2つのテーブルに対してクエリを実行するときです。

一方、読み取りと書き込みの比率が100(またはそれ以上)の一般的な大規模でビジーなデータベースでは、ダーティリードを使用しないすべての単一(読み取り)クエリは、取得して確認する必要があるため、システムの速度を低下させます。ロックの場合、およびトランザクションが失敗する可能性が高くなり(通常はデッドロックが原因)、データベースの整合性の問題がさらに深刻になる可能性があります。

代わりに、ダーティリードを使用すると、システムの速度と信頼性が大幅に向上します(パフォーマンスの向上により、矛盾が発生する可能性が低くなります)。

もちろん、使用してはならない場合もあります。データベースをデフォルトでREAD UNCOMMITTED分離レベルを使用するように設定したり、SQLスクリプトやSPの開始時に明示的なSET TRANSACTION ISOLATION LEVEL READ UNCOMMITTEDステートメントを使用したりするのが嫌いです-ダーティリードが発生する可能性が高すぎますすべきではない。代わりに、(NOLOCK)ヒントは、プログラマが自分のやっていることを考えており、この特定のクエリのこの特定のテーブルではダーティリードが安全であると判断したため、はるかに優れたアプローチです。

ある銀行口座から別の銀行口座に送金するようにアプリケーションをプログラミングしている場合は、ダーティーリードを使用しないでください。しかし、ほとんどのアプリケーションはそのレベルのパラノイアを必要としません。

1
Simon Holzman