Deadlocks in Oracle

前端 未结 2 825
长发绾君心
长发绾君心 2020-12-17 08:08

I want to make a script where the oracle sessions which go into a deadlock are killed automatically.Is it possible to find out the session id for the sessions which go int

相关标签:
2条回答
  • 2020-12-17 08:56

    user 1

    update table_c set id = 200 where id = 13;
    BEGIN
    DBMS_LOCK.sleep(14);
    END;
    /
    update table_c set id = 200 where id = 15;
    

    user 2

    update table_c set id = 2000 where id = 15;
    
    BEGIN
    DBMS_LOCK.sleep(14);
    END;
    /
    
    update table_c set id = 1000 where id = 13; 
    
    0 讨论(0)
  • 2020-12-17 08:58

    I want to make a script where the oracle sessions which go into a deadlock are killed automatically

    EDIT Explained in a better way, corrected few sentences, and added a test case to demonstrate deadlock scenario.

    Why do you want to re-invent the wheel? Oracle detects a deadlock automatically, throws ORA-00060: deadlock detected while waiting for resource, and rolls back one of the transactions involved in the deadlock which Oracle decided as the victim. The previous successful transactions are not rolled back. Even after the deadlock error, if a commit is issued, the previous successful transaction will be committed. At this time, the other session's transaction will also succeed and you could issue a commit. There is nothing that you need to explicitly do here. Deadlocks are automatically cleared -- you never need to clear them.

    Usually, Oracle takes a second or two to detect a deadlock and throws the error.

    You can try with a simple test case as demonstrated here : Understanding Oracle Deadlock

    Let's look at a test case -

    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
    

    Note the time of each transaction, I have set time on timing on for a better understanding.

    SESSION : 1

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

    SESSION : 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;
    

    At this point, SESSION 2 keeps waiting.

    SESSION : 1

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

    At this point, SESSION 2 is the victim of deadlock, SESSION 1 is still waiting.

    Let's look at the session details from SESSION 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>
    

    So, v$session details when viewed in SESSION 2, i.e. SID 14, says the status is ACTIVE.

    Let's look at the session details from another session, lets call it SESSION 3 for the sake. Remember, SESSION 1 is still waiting.

    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>
    

    So, for other sessions, SESSION 2, i.e. SID 14, is INACTIVE. SESSION 1 is still WAITING with event enq: TX - row lock contention.

    Let's commit SESSION 2 -

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

    At this point, the lock is released for SESSION 1, let's commit session 1 as well -

    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 shows SESSION 1 was waiting that long till SESSION 2 was committed.

    To summarize, here is the entire story of session 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>
    

    To summarize, here is the entire story of session 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>
    

    Now, let's see which transaction actually got rolled back and which got committed -

    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>
    

    Conclusion

    In my opinion, the best way to know the session details of a deadlock is to log the details as verbose as possible. Else, it is a nightmare for a DBA to investigate without proper information logged. For that matter, even a Developer would find it to be an herculean task to rectify and fix the actual design flaw if the deadlock error details are not logged verbosely. And to conclude with a one liner statement, A deadlock is due to design flaw, Oracle is just the victim and the application being the culprit. Deadlocks are scary, but they point out the design flaws that must be rectified sooner or later.

    0 讨论(0)
提交回复
热议问题