sql >> データベース >  >> RDS >> Oracle

Oracleのデッドロック

    デッドロックに陥ったオラクルセッションが自動的に強制終了されるスクリプトを作成したい

    編集 より良い方法で説明し、いくつかの文を修正し、デッドロックシナリオを示すためのテストケースを追加しました。

    なぜあなたは車輪の再発明をしたいのですか? Oracleはデッドロックを自動的に検出し、ORA-00060: deadlock detected while waiting for resourceをスローします。 、およびOracleが被害者として決定したデッドロックに関連するトランザクションの1つをロールバックします。以前に成功したトランザクションはロールバックされません。デッドロックエラーが発生した後でも、コミットが発行されると、前に成功したトランザクションがコミットされます。このとき、他のセッションのトランザクションも成功し、コミットを発行できます。 ここで明示的に行う必要があることは何もありません。デッドロックは自動的にクリアされます。クリアする必要はありません。 それら。

    通常、Oracleはデッドロックを検出してエラーをスローするのに1〜2秒かかります。

    ここに示されているように、簡単なテストケースで試すことができます:OracleDeadlockについて

    テストケースを見てみましょう-

    SQL> CREATE TABLE t_test(col_1 NUMBER, col_2 NUMBER);
    
    Table created
    SQL> INSERT INTO t_test VALUES(1,2);
    
    1 row inserted
    SQL> INSERT INTO t_test VALUES(3,4);
    
    1 row inserted
    
    SQL> COMMIT;
    
    Commit complete
    
    SQL> SELECT * FROM t_test;
    
         COL_1      COL_2
    ---------- ----------
             1          2
             3          4
    

    各トランザクションの時刻に注意してください。理解を深めるために、タイミングをオンに設定しました。

    セッション:1

    12:16:06 SQL> UPDATE t_test SET col_1 = 5 WHERE col_2=2;
    
    1 row updated.
    
    Elapsed: 00:00:00.00
    

    セッション:2

    12:16:04 SQL> UPDATE t_test SET col_1 = 6 WHERE col_2=4;
    
    1 row updated.
    
    Elapsed: 00:00:00.00
    12:16:31 SQL> UPDATE t_test SET col_1 = 7 WHERE col_2=2;
    

    この時点で、セッション2は待機し続けます

    セッション:1

    12:16:15 SQL> UPDATE t_test SET col_1 = 8 WHERE col_2=4;
    

    この時点で、セッション2 デッドロックの犠牲者です、セッション1 まだ待っています。

    セッション2のセッションの詳細を見てみましょう -

    12:22:15 SQL> select sid,status,program,sql_id, state, wait_class, blocking_session_status, event from v$session where schemaname='LALIT' and program='sqlplus.exe';
    
           SID STATUS   PROGRAM         SQL_ID        STATE               WAIT_CLASS      BLOCKING_SE EVENT
    ---------- -------- --------------- ------------- ------------------- --------------- ----------- ----------------------------------------------------------------
            14 ACTIVE   sqlplus.exe     60qmqpmbmyhxn WAITED SHORT TIME   Network         NOT IN WAIT SQL*Net message to client
           134 ACTIVE   sqlplus.exe     5x0zg4qwus29v WAITING             Application     VALID       enq: TX - row lock contention
    
    Elapsed: 00:00:00.00
    12:22:18 SQL>
    

    したがって、v$session セッション2で表示した場合の詳細 、つまりSID 14は、ステータスがアクティブであることを示しています 。

    別のセッションのセッションの詳細を見てみましょう。セッション3と呼びましょう。 のための。 セッション1を忘れないでください まだ待っています。

    SQL> set time on timing on
    12:24:41 SQL> select sid,status,program,sql_id, state, wait_class, blocking_session_status, event from v$session where schemaname='LALIT' and program='sqlplus.exe'
    
           SID STATUS   PROGRAM         SQL_ID        STATE               WAIT_CLASS BLOCKING_SE EVENT
    ---------- -------- --------------- ------------- ------------------- ---------- ----------- ------------------------------
            13 ACTIVE   sqlplus.exe     60qmqpmbmyhxn WAITED SHORT TIME   Network    NOT IN WAIT SQL*Net message to client
            14 INACTIVE sqlplus.exe                   WAITING             Idle       NO HOLDER   SQL*Net message from client
           134 ACTIVE   sqlplus.exe     5x0zg4qwus29v WAITING             Applicatio VALID       enq: TX - row lock contention
                                                                          n
    
    
    Elapsed: 00:00:00.01
    12:24:44 SQL>
    

    したがって、他のセッションについては、セッション2 、つまりSID14は非アクティブです 。 セッション1 まだ待機中 イベントenq: TX - row lock contention

    セッション2をコミットしましょう -

    12:22:18 SQL> commit;
    
    Commit complete.
    
    Elapsed: 00:00:00.01
    12:25:43 SQL>
    

    この時点で、セッション1のロックが解除されます。 、セッション1もコミットしましょう-

    12:16:15 SQL> UPDATE t_test SET col_1 = 8 WHERE col_2=4;
    
    1 row updated.
    
    Elapsed: 00:08:27.29
    12:25:43 SQL> commit;
    
    Commit complete.
    
    Elapsed: 00:00:00.00
    12:26:26 SQL>
    

    Elapsed: 00:08:27.29 セッション1を表示します セッション2までずっと待っていました コミットされました。

    要約すると、これがセッション1の全体像です -

    12:16:06 SQL> UPDATE t_test SET col_1 = 5 WHERE col_2=2;
    
    1 row updated.
    
    Elapsed: 00:00:00.00
    12:16:15 SQL> UPDATE t_test SET col_1 = 8 WHERE col_2=4;
    
    1 row updated.
    
    Elapsed: 00:08:27.29
    12:25:43 SQL> commit;
    
    Commit complete.
    
    Elapsed: 00:00:00.00
    12:26:26 SQL>
    

    要約すると、これがセッション2の全体像です -

    12:16:04 SQL> UPDATE t_test SET col_1 = 6 WHERE col_2=4;
    
    1 row updated.
    
    Elapsed: 00:00:00.00
    12:16:31 SQL> UPDATE t_test SET col_1 = 7 WHERE col_2=2;
    UPDATE t_test SET col_1 = 7 WHERE col_2=2
                                      *
    ERROR at line 1:
    ORA-00060: deadlock detected while waiting for resource
    
    
    Elapsed: 00:00:24.47
    12:22:15 SQL> select sid,status,program,sql_id, state, wait_class, blocking_session_status, event from v$session where schemaname='LALIT' and program='sqlplus.exe';
    
           SID STATUS   PROGRAM         SQL_ID        STATE               WAIT_CLASS      BLOCKING_SE EVENT
    ---------- -------- --------------- ------------- ------------------- --------------- ----------- ----------------------------------------------------------------
            14 ACTIVE   sqlplus.exe     60qmqpmbmyhxn WAITED SHORT TIME   Network         NOT IN WAIT SQL*Net message to client
           134 ACTIVE   sqlplus.exe     5x0zg4qwus29v WAITING             Application     VALID       enq: TX - row lock contention
    
    Elapsed: 00:00:00.00
    12:22:18 SQL> commit;
    
    Commit complete.
    
    Elapsed: 00:00:00.01
    12:25:43 SQL>
    

    それでは、実際にロールバックされたトランザクションとコミットされたトランザクションを見てみましょう。 -

    12:25:43 SQL> select * from t_test;
    
         COL_1      COL_2
    ---------- ----------
             5          2
             8          4
    
    Elapsed: 00:00:00.00
    12:30:36 SQL>
    

    結論

    私の意見では、デッドロックのセッションの詳細を知る最良の方法は、可能な限り詳細をログに記録することです。そうでなければ、適切な情報を記録せずにDBAが調査するのは悪夢です。さらに言えば、デッドロックエラーの詳細が詳細に記録されていない場合、開発者でさえ、実際の設計上の欠陥を修正して修正するのは非常に困難な作業であることがわかります。そして、ワンライナーステートメントで締めくくります。デッドロックは設計上の欠陥によるものです。 Oracleは被害者であり、アプリケーションが原因です。デッドロックは恐ろしいものですが、遅かれ早かれ修正しなければならない設計上の欠陥を指摘しています。



    1. SQLServerインスタンス上のすべてのデータベースから主キー制約のリストを取得する方法-SQLServer/TSQLチュートリアルパート60

    2. Djangoフィクスチャが失敗し、DatabaseError:値が長すぎて文字が変化しない(50)

    3. UTC_TIMEの例– MySQL

    4. バンドルの失敗-PostgreSQLクライアントライブラリ(libpq)が見つかりません