web-dev-qa-db-ja.com

SELECTクエリのSQL Serverロックを理解する

そのテーブルに影響を与える他のクエリがSELECTクエリのみである場合、テーブルでSELECT WITH (NOLOCK)を使用するメリットは何かと思います。

SQL Serverはどのように処理しますか? SELECTクエリは別のSELECTクエリをブロックしますか?

SQL Server 2012とLinq-to-SQL DataContextを使用しています。

(編集)

パフォーマンスについて:

  • 2番目のSELECTは、ロックされたSELECTを使用している場合、1番目のSELECTが完了するのを待つ必要がありますか?
  • SELECT WITH (NOLOCK)と対?
67
Francis P

SQL ServerのSELECTは、テーブル行に共有ロックを配置します。2番目のSELECTも共有ロックを必要とし、これらは相互に互換性があります。

したがって、1つのSELECTは別のSELECTをブロックできません。

WITH (NOLOCK)クエリヒントの使用目的は、(別の接続によって)挿入処理中のデータを読み取ることができ、まだコミットされていないことです。

そのクエリヒントがないと、行にexclusiveロックを配置する進行中のSELECT(またはINSERT)ステートメントによって、テーブルの読み取りがUPDATEによってブロックされる場合があります(またはその操作のトランザクションがコミット(またはロールバック)されるまで、おそらくテーブル全体)。

WITH (NOLOCK)ヒントの問題:最後に(INSERTトランザクションがロールバックされた場合)まったく挿入されないデータ行を読み取っている可能性があります。レポートには、実際にデータベースにコミットされていないデータが表示される場合があります。

役に立つかもしれない別のクエリヒントがあります-WITH (READPAST)。これは、読み取りを試行し、排他的にロックされている行をスキップするようにSELECTコマンドに指示します。 SELECTはブロックせず、コミットされていない「ダーティな」データを読み取りませんが、一部の行をスキップする場合があります。テーブル内のすべての行を表示しません。

149
marc_s

パフォーマンスでは、選択に集中し続けます。
Sharedは読み取りをブロックしません。
共有ロックブロックの更新。
数百の共有ロックがある場合、共有ロックがクリアされるまで待機する必要があるため、排他ロックを取得するにはしばらく時間がかかります。

デフォルトでは、選択(読み取り)は共有ロックを取得します。
共有(S)ロックにより、同時トランザクションがリソースを読み取る(選択する)ことができます。
他の選択に影響を与えない共有ロック(1または1000)。

違いは、nolockと共有ロックが更新または挿入操作に与える影響です。

リソースに共有(S)ロックが存在している間、他のトランザクションはデータを変更できません。

共有ロックは更新をブロックします!
ただし、nolockは更新をブロックしません。

これは、更新のパフォーマンスに大きな影響を与える可能性があります。インサートにも影響します。

ダーティリード(nolock)はただ汚れているように聞こえます。部分的なデータを取得することはありません。更新プログラムがジョンをサリーに変更している場合、ジョリーを取得することはありません。

並行性のために共有ロックをよく使用します。データは読み取られるとすぐに古くなっています。次のミリ秒でSallyに変わるJohnの読み取りは、古いデータです。次のミリ秒にジョンをロールバックするSallyの読み取りは、古いデータです。それはミリ秒レベルです。ユーザーが共有ロックを取得している場合は実行に20時間かかり、ユーザーがロックを取得していない場合は実行に4時間かかるデータローダーがあります。この場合の共有ロックは、データを16時間古いものにします。

Nolockを間違って使用しないでください。しかし、彼らには場所があります。バイトが1に設定されているときにチェックをカットし、チェックがカットされたときに2に設定する場合-ノーロックの時間ではありません。

31
paparazzo

私の仕事では、数十万行、時には数百万行の非常に大きなテーブルで、同時に多くのPCで実行される非常に大きなシステムがあります。

非常に大きなテーブルでSELECTを行う場合、ユーザーが過去10年間に行ったすべてのトランザクションを知りたいとします。テーブルの主キーが効率的な方法で構築されていない場合、クエリには数分かかることがあります走る。

次に、アプリケーションが同じデータベースにアクセスして、多くのユーザーのPCで同時に実行される可能性があります。したがって、誰かが(SQLが読み取ろうとしているページで)他のSELECTが読み取っているテーブルに挿入しようとすると、LOCKが発生し、2つのトランザクションが互いにブロックする可能性があります。

SELECTステートメントに "NO LOCK"を追加する必要がありました。これは、多くのユーザーが同時に多く使用するテーブル上の巨大なSELECTであり、常にLOCKSがあったためです。

私の例が十分に明確かどうかわかりませんか?これは実際の例です。

重要なコメントを追加する必要があります。誰もがNOLOCKはダーティデータのみを読み取ると言及しています。これは正確ではありません。また、同じ行を2回取得したり、読み取り中に行全体がスキップされたりする可能性もあります。理由は、SQL ServerがBツリーを再分散しているときに、同時にいくつかのデータを要求できるからです。

別のスレッドを確認する

https://stackoverflow.com/a/5469238/2108874

http://www.sqlmag.com/article/sql-server/quaere-verum-clustered-index-scans-part-iii.aspx

NOLOCKヒント(またはセッションの分離レベルをREAD UNCOMMITTEDに設定)を使用すると、SQL Serverに一貫性が期待できないことを伝えるため、保証はありません。ただし、「一貫性のないデータ」とは、コミットされていない変更が後でロールバックされたり、トランザクションの中間状態でデータが変更されたりすることを意味するだけではありません。 また、すべてのテーブル/インデックスデータをスキャンする単純なクエリでは、SQL Serverがスキャン位置を失うか、同じ行を2回取得する可能性があります。

7
Milan Matějka

SELECT WITH (NOLOCK)は、コミットされていないデータの読み取りを許可します。これは、データベースにREAD UNCOMMITTED分離レベルを設定するのと同等です。 NOLOCKキーワードを使用すると、データベース全体で分離レベルを設定するよりもきめ細かな制御が可能になります。

ウィキペディアには便利な記事があります: ウィキペディア:分離(データベースシステム)

また、他のstackoverflowの記事でも詳しく説明されています。

2
rghome

ロックなしで選択-挿入される可能性がある/されないレコードを選択します。ダーティデータを読み取ります。

たとえば、トランザクションが1000行を挿入して失敗したとしましょう。

選択すると、1000行が取得されます。

1
Royi Namir