SQL Serverのデッドロックとは何ですか?
デッドロックの問題とその解決方法を教えてください。
一般に、デッドロックとは、2つ以上のエンティティが一部のソースをブロックしており、循環的な方法でソースをブロックしているため、どれも完了できないことを意味します。
1つの例:テーブルAとテーブルBがあるとします。AとBでいくつかの更新を行う必要があり、使用時に両方をロックすることにしました(これは本当に愚かな動作ですが、現在は目的を果たしています)。 。同時に、誰かが同じことを逆の順序で行います-最初にBをロックし、次にAをロックします。
年代順に、これは起こります:
proc1:ロックA
proc2:ロックB
proc1:ロックB-proc2がBを解放するまで待機を開始します
proc2:ロックA-proc1がAを解放するまで待機を開始します
どちらも終了しません。それはデッドロックです。実際には、クエリが永久にハングすることは望ましくないため、通常はタイムアウトエラーが発生し、基になるシステム(データベースなど)は、時間内に完了しないクエリを強制終了します。
デッドロックの実例の1つは、家の鍵を車に、車の鍵を家にロックする場合です。
デッドロックは、2人のユーザーが複数のリソースを実行する必要があり、一部のリソースが各ユーザーによってロックされている場合に発生します。これは、Aが何かBがなければ実行できないという事実につながり、逆もまた同様です。
Person AとPerson Bがあるとします。どちらも実行するために2つの行(Row1とRow2)を取得する必要があります。
Row2が必要なため、人物Aは実行できません。Row1が必要なため、人物Bは実行できません。他の人が必要としているものをロックしているため、どちらの人も実行できません。
デッドロックを減らすための合理的にシンプルな方法の1つは、すべての複雑なトランザクションで、同じ順序で操作を実行する必要があります。つまり、同じ順序でTable1とTable2にアクセスします。これは、発生するデッドロックの数を減らすのに役立ちます。
この記事 で説明したように、次の図に示すように、2つのトランザクションが互いにロックを解放するのを待つために2つの同時トランザクションが進行できない場合、デッドロックが発生します。
どちらのトランザクションもロック取得フェーズにあるため、どちらも次のトランザクションを取得する前にロックを解放します。
ロックに依存する同時実行制御アルゴリズムを使用している場合、常にデッドロック状態で実行されるリスクがあります。デッドロックは、データベースシステムだけでなく、あらゆる同時実行環境で発生する可能性があります。
たとえば、マルチスレッドプログラムは、2つ以上のスレッドが以前に取得されたロックを待機していて、どのスレッドも進行できない場合、デッドロックする可能性があります。これがJavaアプリケーションで発生した場合、JVMはスレッドにその実行を強制的に停止させ、そのロックを解放させることはできません。
Thread
クラスが stop
メソッドを公開している場合でも、Java 1.1以降、そのメソッドはオブジェクトをスレッドが停止した後、一貫性のない状態のままになる代わりに、Javaはinterrupt
メソッドを定義します。これは、割り込みを受けたスレッドが単に割り込みを無視できるため、ヒントとして機能しますそしてその実行を続けます。
このため、Javaアプリケーションはデッドロック状態から回復できません。デッドロックが発生しないようにロック取得要求を順序付けるのはアプリケーション開発者の責任です。
ただし、特定のトランザクションがさらに取得したい他のロックを予測することは不可能であるため、データベースシステムは特定のロック取得順序を強制できません。ロック順序の保持はデータアクセス層の責任となり、データベースはデッドロック状態からの回復のみを支援できます。
データベースエンジンは、現在の競合グラフをスキャンしてロック待機サイクル(デッドロックが原因)をスキャンする別のプロセスを実行します。サイクルが検出されると、データベースエンジンは1つのトランザクションを選択して中止し、そのロックを解放して、他のトランザクションが進行できるようにします。
JVMとは異なり、データベーストランザクションはアトミックな作業単位として設計されています。したがって、ロールバックによってデータベースは一貫した状態になります。
データベースは、スタックしている2つのトランザクションのいずれかをロールバックすることを選択しますが、どのトランザクションがロールバックされるかを常に予測できるとは限りません。経験則として、データベースは、より低いロールバックコストでトランザクションをロールバックすることを選択する場合があります。
Oracleドキュメント によると、ロールバックを検出したトランザクションは、ステートメントがロールバックされるトランザクションです。
SQL Serverでは、 _DEADLOCK_PRIORITY
_ セッション変数を使用して、デッドロックの状況でどのトランザクションがロールバックされる可能性が高いかを制御できます。
_DEADLOCK_PRIORITY
_セッションは、-10〜10の任意の整数、またはLOW (-5)
、NORMAL (0)
、HIGH (5)
などの定義済みの値を受け入れることができます。
デッドロックの場合、他のトランザクションのデッドロック優先順位の値が低い場合を除き、現在のトランザクションはロールバックされます。両方のトランザクションの優先度の値が同じ場合、SQL Serverは最小のロールバックコストでトランザクションをロールバックします。
ドキュメント で説明されているように、PostgreSQLはどのトランザクションがロールバックされるかを保証しません。
MySQLは リート数のレコードを変更したトランザクションをロールバックします を試みます。これは、リリースするロックの数が少ないほどコストが低くなるためです。
このトピックの詳細については、 この記事 も確認してください。
2つ(またはそれ以上)のトランザクションが、他のトランザクションが保持しているロックが解放されるのをそれぞれ待機しているときに発生する問題。