誰かwith (nolock)
がクエリで使用することの意味を説明することはできますか?
たとえば、トランザクション率が高く、特定のテーブルに大量のデータが含まれるバンキングアプリケーションがある場合、どのタイプのクエリでノーロックでも問題ありませんか?常に使用すべき/使用しないというケースはありますか?
誰かwith (nolock)
がクエリで使用することの意味を説明することはできますか?
たとえば、トランザクション率が高く、特定のテーブルに大量のデータが含まれるバンキングアプリケーションがある場合、どのタイプのクエリでノーロックでも問題ありませんか?常に使用すべき/使用しないというケースはありますか?
回答:
WITH(NOLOCK)は、トランザクション分離レベルとしてREAD UNCOMMITEDを使用するのと同じです。そのため、後でロールバックされるコミットされていない行、つまりデータベースに入れられなかったデータを読み取るリスクがあります。したがって、他の操作による読み取りのデッドロックを防ぐことができますが、リスクが伴います。トランザクション率の高い銀行アプリケーションでは、それをIMHOで解決しようとしている問題の適切な解決策にはならないでしょう。
NOLOCK
と一緒に使用するとSELECT
、選択中にデータがテーブルに挿入(または更新)された場合に同じ行(重複データ)を複数回返すリスクがあります。
問題はもっと悪いことです:
財務データベースの場合、デッドロックは間違った値よりもはるかに悪いです。私はそれが逆に聞こえることを知っていますが、私に聞いてください。DBトランザクションの従来の例では、2つの行を更新し、1つの行から減算して別の行に追加します。それは間違いです。
財務データベースでは、ビジネストランザクションを使用します。つまり、各アカウントに1行追加します。これらのトランザクションが完了し、行が正常に書き込まれることが最も重要です。
アカウントの残高を一時的に間違って取得することは大したことではありません。それが、1日の調整の目的です。また、2つのATMが同時に使用されているため、データベースからのコミットされていない読み取りよりも、アカウントからの当座借越が発生する可能性がはるかに高くなります。
そうは言っても、SQL Server 2005はNOLOCK
必要になったほとんどのバグを修正しました。したがって、SQL Server 2000以前を使用している場合を除き、必要ありません。
さらに詳しい
行レベルのバージョン管理
残念ながら、それはコミットされていないデータを読み取ることだけではありません。バックグラウンドでは、ページを2回読む(ページ分割の場合)か、ページを完全に見逃す可能性があります。そのため、結果が著しく歪んでいる可能性があります。
チェックアウトItzikベン・ガンの記事を。ここに抜粋があります:
"NOLOCKヒントを使用して(またはセッションの分離レベルをREAD UNCOMMITTEDに設定して)、SQL Serverに一貫性を期待しないことを通知します。そのため、保証はありません。ただし、"一貫性のないデータ "は、後でロールバックされたコミットされていない変更、またはトランザクションの中間状態でのデータ変更が表示される場合があります。また、すべてのテーブル/インデックスデータをスキャンする単純なクエリで、SQL Serverがスキャン位置を失うか、結果的に同じ行を2回取得します。」
金融取引をデータベーストランザクションでラップしない理由がわからない(ある口座から別の口座に資金を移動するとき-一度に取引の片側をコミットしない-これが明示的な取引が存在する理由です)。コードがビジネストランザクションのように頭の痛い場合でも、すべてのトランザクションデータベースは、エラーや障害が発生したときに暗黙のロールバックを実行する可能性があります。この議論はあなたの頭上にある方法だと思います。
ロックの問題がある場合は、バージョニングを実装し、コードをクリーンアップします。
ロックなしでは、誤った値が返されるだけでなく、幻のレコードと重複が返されます。
クエリの実行が常に速くなるというのはよくある誤解です。テーブルに書き込みロックがない場合、違いはありません。テーブルにロックがある場合、クエリは速くなりますが、そもそもロックが発明された理由があります。
公平を期して、nolockヒントが実用性を提供する2つの特別なシナリオを次に示します。
1)ライブOLTPデータベースに対して長いクエリを実行する必要がある2005年より前のSQLサーバーデータベース
2)レコードをロックし、制御をUIに戻す不適切に記述されたアプリケーションとリーダーは、無期限にブロックされます。アプリケーションを修正できない場合(サードパーティなど)、データベースが2005年より前であるか、バージョン管理をオンにできない場合は、ここでNolockが役立ちます。
NOLOCK
はと同等ですがREAD UNCOMMITTED
、MicrosoftはUPDATE
or DELETE
ステートメントに使用しないでくださいと言っています:
UPDATEまたはDELETEステートメントの場合:この機能は、Microsoft SQL Serverの将来のバージョンで削除される予定です。新しい開発作業ではこの機能を使用せず、現在この機能を使用しているアプリケーションの変更を計画してください。
http://msdn.microsoft.com/en-us/library/ms187373.aspx
この記事はSQL Server 2005に適用されるため、NOLOCK
そのバージョンを使用している場合はのサポートが存在します。(ダーティリードの使用を決定したと仮定して)コードを将来にわたって使用するために、これをストアドプロシージャで使用できます。
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
データを読み取るだけの場合に使用でき、まだコミットされていないデータを取得するかどうかは特に気にしません。
読み取り操作の方が高速になる可能性がありますが、実際にはどの程度かはわかりません。
一般に、私はそれを使用しないことをお勧めします-コミットされていないデータを読み取ることは、せいぜい少し混乱する可能性があります。
通常は問題ないもう1つのケースは、データがおそらく古く、書き込みが行われないレポートデータベースです。ただし、この場合、デフォルトの分離レベルを変更して、管理者がデータベースまたはテーブルレベルでオプションを設定する必要があります。
一般的なケースでは:あなたがしているとき、あなたはそれを使用することができ非常に確認してください、それは古いデータを読み取るために大丈夫だということ。覚えておかなければならない重要なことは、それを誤解するのは非常に簡単なことです。たとえば、クエリを作成する時点で問題がなくても、これらの更新をより重要にするために、将来データベースで何かが変更されることはないと確信していますか?
また、銀行のアプリではそれはおそらく良い考えではないという考えも2つ目にします。または在庫アプリ。またはトランザクションについて考えているところはどこでも。
簡単な答え-SQLがデータを変更しておらず、(ロックを介して)他のアクティビティに干渉する可能性があるクエリがある場合。
特にクエリが1秒以上かかる場合は、レポートに使用されるクエリを検討する価値があります。
これは、OLTPデータベースに対して実行しているOLAPタイプのレポートがある場合に特に便利です。
しかし、最初に尋ねる質問は、「なぜこれを心配しているのですか?」です。私の経験では、デフォルトのロック動作の曖昧さは、誰かが「何かを試す」モードにあるときにしばしば発生します。これは、予期しない結果が発生する可能性が低いケースの1つです。多くの場合、これは時期尚早の最適化のケースであり、「念のため」にアプリケーションに埋め込まれたままにしておくのは簡単すぎる可能性があります。なぜそれを行っているのか、どのような問題が解決されているのか、そして実際に問題があるのかどうかを理解することが重要です。
簡潔な答え:
WITH (NOLOCK)
クラスタ化インデックスを持つテーブルのSELECTステートメントでのみ使用します。
長い答え:
WITH(NOLOCK)は、データベースの読み取りを高速化する魔法の方法としてよく利用されます。
結果セットには、まだコミットされていない、後でロールバックされることが多い行を含めることができます。
WITH(NOLOCK)が非クラスター化インデックスを持つテーブルに適用される場合、行データが結果テーブルにストリーミングされるときに、他のトランザクションによって行インデックスを変更できます。これは、結果セットで行が欠落したり、同じ行が複数回表示されたりする可能性があることを意味します。
READ COMMITTEDは、複数のユーザーが同じセルを同時に変更する単一の列内でデータが破損するという追加の問題を追加します。
READ UNCOMITTED
も影響はありません。ANSI規格に含まれているのには理由があります。
私の2セント- WITH (NOLOCK
レポートを生成する必要があるときに使用するのは理にかなっています。この時点では、データはあまり変化せず、それらのレコードをロックする必要はありません。
あなたが金融取引を扱っているなら、あなたは決して使いたくないでしょうnolock
。 nolock
更新が多い大きなテーブルから選択するのに最適であり、取得したレコードが古くなっている可能性があるかどうかは気にしません。
財務レコード(およびほとんどのアプリケーションの他のほとんどすべてのレコード)nolock
は、書き込み中のレコードからデータを読み取る可能性があり、正しいデータを取得できない可能性があるため、大混乱を引き起こします。
私は、やることのために「次のバッチ」を取得するために使用しました。この場合、どのアイテムが正確であるかは関係ありません。多くのユーザーが同じクエリを実行しています。
特に(nolock)ヒントを使用して、アクティビティの多いSQLServer 2000データベースで使用します。ただし、SQL Server 2005で必要になるかどうかはわかりません。私は最近、クライアントのDBAの要求に応じてSQL Server 2000にそのヒントを追加しました。彼が多くのSPIDレコードロックに気付いていたからです。
私が言えることは、ヒントを使用しても害はなく、ロックの問題が解決したようだということです。その特定のクライアントのDBAは、基本的にはヒントを使用するように要求しました。
ちなみに、私が扱っているデータベースはエンタープライズメディカルクレームシステムのバックエンドなので、多くの結合で数百万のレコードと20以上のテーブルについて話しています。通常、結合の各テーブルにWITH(nolock)ヒントを追加します(派生テーブルでない限り、その特定のヒントは使用できません)。