web-dev-qa-db-ja.com

単一の行を更新/挿入するとき、テーブル全体をロックする必要がありますか?

トランザクション上にあり、同じテーブルにアクセスするが、それらのテーブルの行を完全に分離する2つの長時間実行クエリがあります。また、これらのクエリは、それらのクエリに基づいていくつかの更新と挿入を実行します。

これらが同時に実行されると、何らかのロックが発生し、行の1つを更新するときにタスクが完了せず、ロックされるように見えます。読み取り中の行に対して排他的な行ロックを使用していますが、プロセスに表示されるロックはlck_m_ixロックです。

2つの質問:

  1. 単一の行を更新/挿入すると、テーブル全体がロックされますか?
  2. この種の問題を回避するために何ができますか?
26
Middletone

通常はありませんが、それは異なります(SQL Serverで最もよく使用される答えです!)

SQL Serverは、何らかの方法でトランザクションに関係するデータをロックする必要があります。変更を実行している間、テーブル自体のデータと、影響を受けるインデックスのデータをロックする必要があります。同時実行性を改善するために、複数のプロセスの実行を許可するために、サーバーが使用することを決定するロックの「粒度」がいくつかあります。行ロック、ページロック、およびテーブルロックが一般的です(もっとあります)。ロックの規模は、サーバーが特定の更新を実行する方法を決定する方法によって異なります。物事を複雑にしているのは、ロックされたオブジェクトを読み取ったり変更したりできるかどうかを制御する、共有、排他、意図排他などのロックの分類もあります。

私の経験では、SQL Serverは主にテーブルの小さな部分への変更にページロックを使用し、テーブルの大部分が(統計から)更新の影響を受けていると思われる場合、しきい値を超えると自動的にテーブルロックにエスカレートします削除します。アイデアは、大きな更新のために数千の個別の行またはページロックを取得して管理するよりも、テーブルをロックする(1つのロック)方が速いということです。

特定のケースで何が起こっているかを確認するには、クエリロジックを確認し、実行中にsys.dm_tran_locks、sys.dm_os_waiting_tasksまたは他のDMVのロック/ブロック条件を調べる必要があります。各プロセスのどのステップで何がロックされているのかを正確に発見し、一方が他方をブロックしている理由を発見したいと思うでしょう。

22
onupdatecascade

ショートバージョン:

  1. 番号
  2. コードを修正してください。

ロングバージョン:

LCK_M_IXはインテントロックです。つまり、操作は下位要素にXロックを設定します。例えば。テーブルの行を更新するとき、操作テーブルは、更新/挿入/削除される行をXにロックする前に、テーブルのIXロックを取得します。ロックマネージャーはロックが要求されたリソースの物理構造を理解できないため(つまり、ページP1のXロックがR1はP1)に含まれているため、行R1のSロック。詳細については、「 ロックモード 」を参照してください。

インテントロックで競合が発生しているという事実は、テーブルロックのような高レベルのオブジェクトロックを取得しようとしていることを意味します。ブロックされているリクエスト(LCK_M_IXと互換性のないロックをリクエストしているリクエスト)のソースコードを分析し、オブジェクトレベルのロックリクエストの原因を取り除く必要があります。それが意味することはあなたのソースコードに依存します、私はあなたがそこで何をしているのかわかりません。私の推測では、誤ったロックヒントを使用しています。

より一般的なアプローチは、 SNAPSHOT ISOLATION に依存することです。しかし、スナップショットの分離は行レベルの競合の問題のみに効果があり、テーブルのロックを要求するアプリケーションには効果がないため、これはおそらく発生している問題を解決しません。

20
Remus Rusanu

トランザクションを頻繁に使用する目的:できるだけ短く、甘くしてください。私はあなたが取引を開始し、それからいろいろなことをするという質問であなたの言葉遣いから感覚を得ます。そのいくつかは長い時間がかかります。次に、複数のユーザーがこの同じコードを同時に実行できることを期待します。残念ながら、そのコードセットの先頭で挿入を実行し、コミットまたはロールバックする前に他の40の操作を実行すると、その挿入によって他の人が同じタイプの挿入を実行できなくなり、基本的に操作がすべて無料でシリアルに。

各クエリが何をしているのか、予期しないロックのエスカレーションが発生しているのかを調べます。クエリでWITH(ROWLOCK)と言うからといって、SQL Serverが準拠できるわけではありません...複数のインデックス、インデックス付きビュー、永続化された計算列などに触れた場合、行ロックにはさまざまな理由があります水を保持することはできません。また、トランザクションの後半で考えているよりも時間がかかっていることがあります。また、トランザクションに関係するすべてのオブジェクト(現在実行中のステートメントだけでなく)のロックを保持できることに気付かない場合があります。トランザクションの期間。

11
Aaron Bertrand

データベースごとにロックメカニズムは異なりますが、SQL ServerやOracleなどのロックメカニズムにはさまざまなタイプがあります。

SQL Serverのデフォルトはペシミスティックページロックのようです。そのため、レコード数が少ない場合、すべてのレコードがロックされる可能性があります。

ほとんどのデータベースはスクリプトの実行時にロックされないため、トランザクションなしで複数のクエリを同時に実行する可能性があるのではないかと考えています。

1
David Burton