web-dev-qa-db-ja.com

NOLOCKは常に悪いですか?

私はクエリをできる限り効率的にしたいレポート開発者です。以前はDBAと一緒に仕事をしていて、本番サーバーのレポートを常に扱っていたので、すべてのクエリでNOLOCKを使用するように言われました。

現在、私は、どのような状況でもNOLOCKを禁止しているDBAと協力しています-私のレポートが(いくつかのテーブルのインデックスがかなり不足しているため)レプリケーションとシステムの更新を停止している場合でも。私の意見では、この場合、NOLOCKは良いことです。

私のSQLトレーニングのほとんどは非常に異なる意見を持つさまざまなDBAに来たので、私はこれをさまざまなDBAに尋ねたかったのです。

34
DataGirl

レポートがDBAの正しい更新をブロックしている場合は、NOLOCKを絶対に使用しないでください。 areの競合があるという事実自体が、不正なレポートを取得するダーティリードを使用します。

私の意見では、NOLOCKよりも優れた代替手段が常にあります。

  • プロダクションテーブルは読み取り専用であり、変更されることはありませんか?データベースを読み取り専用としてマークしてください!
  • テーブルスキャンによりロックの競合が発生しますか?テーブルに適切にインデックスを付けます。メリットは複数あります。
  • 適切にインデックスを作成する方法を変更できません/わかりませんか? SNAPSHOT ISOLATION を使用します。
  • スナップショットを使用するようにアプリを変更できませんか?オンにする コミットされたスナップショットを読み取る
  • 行のバージョン管理の影響を測定し、それがパフォーマンスに影響を与えるという証拠はありますか?データにインデックスを付けることができませんか?そして、あなたは大丈夫です 不正なレポート ?次に、少なくとも自分自身を支持して使用してください SET TRANSACTION ISOLATION LEVEL 、クエリヒントではありません。すべてのクエリを変更するよりも、後で分離レベルを修正する方が簡単です。
31
Remus Rusanu

それは常に悪いことではありません。

もちろん、コミットされていない値(ロールバックされる可能性があり、したがって論理的に存在することはない)を読み取ることができ、値を複数回読み取る、またはまったく読み取らないなどの現象を許可することもできます。

このような異常が発生しないことを保証する唯一の分離レベルは、シリアライズ可能/スナップショットです。スキャンがこの行に到達する前に行が(キーの更新により)移動されると、反復可能な読み取り値の下で値が失われる可能性があります。

これらの問題は、nolockで発生する可能性が高くなりますが、デフォルトでは、この分離レベルでは、読み取るページが64ページを超えると推定される場合、割り当て順スキャン が使用されるためです 。インデックスキーの更新が原因で行がページ間を移動するときに発生する問題のカテゴリと同様に、これらの割り当て順スキャンは、ページ分割の問題に対しても脆弱です(新しく割り当てられたページがファイル内でポイントよりも前にある場合、行が失われる可能性があります)既にスキャンされているか、既にスキャンされたページがファイル内の後続のページに分割されている場合は2回読み取られます)。

少なくとも単純な(単一のテーブル)クエリの場合、これらのスキャンの使用を思いとどまらせ、nolockOrderedプロパティがIndexScanになるようにクエリにORDER BY index_keyを追加するだけで、trueでキー順スキャンを取得できます。

しかし、レポート作成アプリケーションが完全に正確な数値を必要とせず、そのような不整合の高い可能性を許容できる場合、それは受け入れられる可能性があります。

しかし、魔法の「ターボ」ボタンであることを期待して、すべてのクエリでそれをチャックするべきではありません。その分離レベルで異常な結果が発生する可能性が高いか、まったく結果がない(「データ移動のためNOLOCKでスキャンを続行できませんでした」エラー)だけでなく、nolockでパフォーマンスが発生する場合もありますはるかに悪化する可能性があります

33
Martin Smith

顧客はレポートの一貫性のない結果を許容していますか?答えが「いいえ」の場合は、NOLOCKを使用しないでください。同時実行で誤った結果が得られる可能性があります。 herehere 、および here の例をいくつか書きました。これらの例は、READ COMMITTEDとREPEATABLE READで一貫性のない出力を示していますが、それらを微調整して、NOLOCKで誤った結果を取得することもできます。

11
A-K

私が作成するレポートのほとんどは、現在のデータでは実行されません。ほとんどの顧客が実行しているレポートは、昨日のデータです。その場合、答えは変わりますか?

その場合は、もう1つの選択肢があります。
本番データベースでクエリを実行してロックとNOLOCKをいじる代わりに、本番データベースのコピーからレポートを実行できます。

毎晩バックアップから自動的に復元されます のように設定できます。
お客様のサイトのサーバーでレポートが実行されているようです。そのため、これを設定することが現実的な解決策になるかどうかはわかりません。
(ただし、繰り返しますが、とにかくバックアップが必要なので、復元に必要なサーバースペースがあれば十分です)

私は社内の開発者なので、サーバーとデータベースを完全に制御できるので、これは私にとっては簡単です。

これは、少なくとも昨日以前のデータのみを必要とするレポートに対して行うことができます。たぶん、一部のレポートは本番データベースに留まる必要がありますが、少なくとも一部の負荷を別のデータベース(またはさらに良いのは別のサーバー)に移動します。

私も仕事で同じ状況にあります:
ほぼすべてのレポートにこのような本番データベースのコピーを使用していますが、今日のデータを必要とするクエリがいくつかあります。

8