web-dev-qa-db-ja.com

SQL Serverの "with(nolock)"とは何ですか?

with (nolock)をクエリに使用することの意味するところを説明してもらえますか。

たとえば、特定のテーブルに高いトランザクションレートと大量のデータを含む銀行取引アプリケーションがある場合、どの種類のクエリでも問題ないでしょうか。あなたはいつもそれを使うべきです/決して使わない場合がありますか?

559
Andy White

WITH(NOLOCK)は、トランザクション分離レベルとしてREAD UNCOMMITEDを使用するのと同じです。そのため、後でロールバックされるコミットされていない行、つまりデータベースに書き込まれなかったデータを読み取る危険性があります。そのため、読み取りが他の操作によってデッドロックされるのを防ぐことはできますが、リスクが伴います。高い取引レートを持つ銀行業務アプリケーションでは、私がそれを使って解決しようとしているどんな問題に対しても正しい解決策にはならないでしょう。

420
David M

問題は、さらに悪いことです。

  • デッドロック、または
  • 間違った値?

金融データベースでは、デッドロックは間違った値よりはるかに悪いです。私はそれが後ろ向きに聞こえることを知っています、しかし私を聞いてください。 DBトランザクションの伝統的な例は、2つの行を更新し、一方から減算し、もう一方に加算することです。それは間違いです。

財務データベースでは取引を使用します。それは各アカウントに1行追加することを意味します。これらのトランザクションが完了し、行が正常に書き込まれることが最も重要です。

アカウントの残高を一時的に誤ったものにしても大したことではありません。それが、1日の終わりに行われる調整です。また、データベースからのコミットされていない読み取りよりも、2つのATMが同時に使用されているため、口座からの当座貸越が発生する可能性がはるかに高くなります。

とは言っても、SQL Server 2005はNOLOCKを必要とするほとんどのバグを修正しました。そのため、SQL Server 2000以前を使用していない限り、必要はありません。

さらに読む
行レベルのバージョン管理

160
Jonathan Allen

Nolockヒントの正当な使用法の教科書の例は、高度な更新プログラムOLTPに対するレポートのサンプリングです。

局所的な例を挙げる。米国の大手ハイストリート銀行が、銀行で都市レベルの最初の兆候を探すために1時間ごとのレポートを作成したい場合、nolockクエリは、都市ごとの現金預金と現金引き出しを合計するトランザクションテーブルをスキャンできます。そのようなレポートでは、ロールバックされた更新トランザクションによって引き起こされるわずかな割合のエラーでも、レポートの価値は下がりません。

52
saasman

残念ながら、コミットされていないデータを読み取るだけではありません。バックグラウンドでは、2回ページを読むことになるかもしれませんし(ページ分割の場合)、あるいはページを全部見逃すかもしれません。だからあなたの結果は大きく歪んでいるかもしれません。

Itzik Ben-Ganの記事 をチェックしてください。これは抜粋です。

「NOLOCKヒントを使用して(またはセッションの分離レベルをREAD UNCOMMITTEDに設定して)、SQL Serverに一貫性を期待しないことを伝えます。したがって、保証はありません。 すべてのテーブル/インデックスデータをスキャンする単純なクエリでは、SQL Serverはスキャン位置を失う可能性があります。同じ行を2回取得することになるかもしれません "

52
sqlbelle

なぜあなたがデータベース取引で金融取引をラッピングしていないのかわからない(ある口座から他の口座へ資金を移転するとき - あなたは一度に取引の一方をコミットしない - これが明示的な取引が存在する理由です)。たとえあなたのコードがそれがそうであるようにビジネストランザクションに頭脳がいっぱいであっても、すべてのトランザクションデータベースはエラーまたは失敗の場合に暗黙のロールバックをする可能性を持っています。私はこの議論はあなたの頭上で道だと思います。

ロックの問題がある場合は、バージョン管理を実装してコードをクリーンアップしてください。

ノーロックは誤った値を返すだけでなく、ファントムレコードと重複を返します。

クエリが常に高速に実行されるというのはよくある誤解です。テーブルに書き込みロックがない場合でも、違いはありません。テーブルにロックがあると、クエリは速くなりますが、そもそもロックが発明されたのには理由があります。

公平を期すために、nolockヒントが有用性を提供する可能性がある2つの特別なシナリオがあります。

1)ライブOLTPデータベースに対して長いクエリを実行する必要がある2005年以前のSQLサーバーデータベースこれが唯一の方法かもしれません

2)レコードをロックし、制御をUIおよび読者に返す、適切に作成されていないアプリケーションは無期限にブロックされます。アプリケーションを修正できず(サードパーティなど)、データベースが2005年より前であるかバージョン管理を有効にできない場合は、ここでNolockが役立ちます。

30
Andrew

NOLOCKREAD UNCOMMITTEDと同等ですが、MicrosoftはUPDATEまたはDELETEステートメントには使用しないでくださいと言っています。

UPDATEまたはDELETEステートメントの場合:この機能は、将来のバージョンのMicrosoft SQL Serverでは削除される予定です。この機能を新しい開発作業に使用することは避け、現在この機能を使用しているアプリケーションを変更することを計画してください。

http://msdn.Microsoft.com/ja-jp/library/ms187373.aspx

この記事はSQL Server 2005に適用されるため、そのバージョンを使用している場合はNOLOCKのサポートが存在します。将来を保証するために(ダーティリードを使用することにしたと仮定して)あなたがコーディングするのであれば、あなたはあなたのストアドプロシージャでこれを使用することができます:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

23
Seibar

データを読んでいるときだけ使用できますが、まだコミットされていないデータを取り戻す可能性があるかどうかはあまり気にしません。

読み込み操作のほうが速くなる可能性がありますが、いくら言っても言えません。

一般的に、私はそれを使用することをお勧めします - コミットされていないデータを読むことはせいぜい少し混乱を招く可能性があります。

18
marc_s

通常は問題がないもう1つのケースは、レポートデータベースにあります。データはすでに古くなっているため、書き込みは発生しません。ただし、この場合は、管理者がデフォルトの分離レベルを変更して、データベースまたはテーブルレベルでオプションを設定する必要があります。

一般的な場合では、あなたは very のときにそれを使うことができます。古いデータを読んでも大丈夫です。覚えておくべき重要なことは、その それを間違えるのは非常に簡単なことです 。たとえば、クエリを作成した時点で大丈夫であっても、これらの更新をより重要にするために将来データベース内で何かが変更されることはないでしょうか。

私はまた、おそらくそれが ではない という銀行用アプリの良い考えであるという考えを2番目にします。または在庫アプリ。あるいは取引を考えているところならどこでも。

17
Joel Coehoorn

簡単な答え - あなたのSQLがデータを変更していない時はいつでも、そしてあなたは他の活動を妨害するかもしれない質問を持っています(ロックを介して)。

特にクエリが1秒以上かかる場合は、レポートに使用されるクエリについて検討する価値があります。

OLTPデータベースに対して実行しているOLAPタイプのレポートがある場合は特に便利です。

しかし、最初に尋ねる質問は、「なぜこれが心配なのか」ということです。私の経験では、誰かが「何でも試す」モードになっているときにデフォルトのロック動作を欺くことがよくありますが、これは予期しない結果が起こる可能性が低い場合の1つです。あまりにも多くの場合、時期尚早の最適化のケースであり、「念のために」アプリケーションに埋め込んだままにしておくことができすぎることがあります。なぜそれをしているのか、どんな問題を解決しているのか、そして実際に問題があるのか​​どうかを理解することは重要です。

14
dkretz

私の2セント - レポートを生成する必要があるときはWITH (NOLOCK)を使うのは意味があります。この時点では、データはそれほど変わらないでしょうし、あなたはそれらのレコードをロックしたくないでしょう。

9
SoftwareGeek

あなたが金融取引を扱っているなら、あなたは決してnolockを使いたくないでしょう。 nolockはたくさんの更新がある大きなテーブルから選択するのに最もよく使われます、そしてあなたが得るレコードがおそらく古くなっているかもしれないかどうかあなたは気にしません。

財務記録(およびほとんどのアプリケーションの他のほとんどすべての記録)の場合、nolockは、書き込まれているレコードからデータを読み戻すことができ、正しいデータを取得できない可能性があるため、混乱を招きます。

8
Andrew Hare

やることのために「次のバッチ」を取得するのが常でした。この場合、どちらのアイテムでも問題ありません。この同じクエリを実行しているユーザーが多数います。

7
Otávio Décio

短い答え:

決してWITH (NOLOCK)を使わないでください。

長い答え:

NOLOCKはデータベースの読み込みを高速化するための魔法のような方法として悪用されることが多くありますが、可能な限り使用しないようにしています。

結果セットには、まだコミットされていない行、後にロールバックされることが多い行を含めることができます。

エラーまたは結果セットは、空、行が欠落している、または同じ行を複数回表示することができます。

これは、読んでいるのと同時に他のトランザクションがデータを移動しているためです。

READ COMMITTEDには、複数のユーザーが同じセルを同時に変更する単一の列内でデータが破損するという追加の問題があります。

他にも副作用があるので、そもそもあなたが望んでいた速度の増加を犠牲にすることになります。

それを避けることができる場所でそれを使用することは問題ないと主張することができますが、ポイントは何ですか?破損したデータが許容できる状況は考えられません。

NOLOCKを使用したことはありません。

(今まで)

6

「ダーティ」データに問題がなければ、nolockを使用してください。つまり、nolockは、変更中のデータやコミットされていないデータも読み取ることができます。

一般にトランザクションの多い環境で使用するのはお勧めできません。そのため、クエリのデフォルトオプションにはなりません。

6
Learning

私は(nolock)ヒントと一緒に、特に活動の多いSQLServer 2000データベースで使用します。私はそれがSQL Server 2005で必要とされているかどうかはわかりません。私は最近、クライアントのDBAからの依頼でSQL Server 2000にそのヒントを追加しました。なぜなら、彼は多くのSPIDレコードロックに気付いていたからです。

私が言えるのは、ヒントを使用しても私たちに害はなく、ロックの問題が解決したように思われるということです。その特定のクライアントのDBAは基本的に私たちがヒントを使うことを主張しました。

ちなみに、私が扱うデータベースは企業の医療保険請求システムのバックエンドなので、何百万ものレコードと20を超えるテーブルについて、さまざまな形で話し合っています。通常、結合の各テーブルにWITH(nolock)ヒントを追加します(派生テーブルではない場合、その特定のヒントは使用できません)。

6
user52212

最も単純な答えは単純な質問です - あなたはあなたの結果が再現可能であることを必要としますか?そうであれば、NOLOCKSはいかなる状況下でも適切ではありません

再現性が必要ない場合は、特にターゲットデータベースに接続するすべてのプロセスを制御できない場合は、nolockが便利です。

3
Ed Green