Skip to Main Content

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Andrew.

Asked: October 08, 2006 - 11:45 am UTC

Last updated: February 09, 2021 - 9:42 am UTC

Version: 10.1.0

Viewed 10K+ times! This question is

You Asked

Hi Tom,

"Oracle Database Concepts 10g" gives us the following explanation of deadlock:

"A deadlock can occur when two or more users are waiting for data locked by each other. Deadlocks prevent some transactions from continuing to work.
.......
It is a deadlock because no matter how long each transaction waits, the conflicting locks are held."

However, let's consider the simple testcase (two sessions try to lock rows of the same table):

S#1> create table test(x) as
2 select 1 from dual
3 union all
4 select 2 from dual;

Table created.

S#1> select * from test
2 where x = 1 for update;

X
----------
1

S#2> select * from test
2 where x = 2 for update;

X
----------
2

S#2> select * from test
2 where x = 1 for update WAIT 60;
-- session 2 hangs ...

S#1> select * from test
2 where x = 2 for update WAIT 60;
-- session 1 hangs ...

Eventually, we get the following feedback in out first session:
select * from test
*
ERROR at line 1:
ORA-30006: resource busy; acquire with WAIT timeout expired


S#1>

But as for second session – result is a bit surprising (at least for me):

select * from test
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource


S#2>

And that's where my doubts are hidden: do we really have deadlock situation here? In both sessions, we just asked Oracle "hey, give me that row in exclusive mode and if it's already locked – wait no more than 60 seconds".

In my opinion, we can expect only two possible outcomes of our requests:
1. Oracle obtains lock we requested.
2. Oracle can not obtain lock as it's concurrently held by some other session. It waits for 60 seconds and then gives up with ORA-30006.

But why deadlock? Let me quote "Concepts" once again:
"It is a deadlock because no matter how long each transaction waits, the conflicting locks are held."

Well, in our example we are NOT in the situation where "no matter how long each transaction waits, the conflicting locks are held". Because we specified timeout, didn't we?

Thanks beforehand for your answer,

Kind regards,
Andrew.

and Tom said...

we have a deadlock there because of the way deadlocks are detected.

The background processes, every three seconds, will wake up and look for any two sessions blocking eachother - such as session 1 was blocking 2 and 2 was blocking 1. It does not matter that one of the sessions would eventually stop blocking the other - that information is not even visible outside of the session itself.

For you see, you are not really blocking "on a row", you are waiting for the transaction to commit. when you get blocked, you enqueue ON THE TRANSACTION itself.


The concepts guide actually seems to be going out of its way here - "no matter how long". It doesn't see that one of them will eventually give up trying, that information just isn't exposed, this will raise a deadlock. Period.


try this to see what i mean about getting blocked on transactions:

session1: lock row 1 with an update
session1: savepoint foo
session1: select for update row 2
session2: select for update row 2 <<== becomes blocked on session 1, ON SESSION 1, not row 2 really...
session1: rollback to savepoint <<< session2, still blocked.
session3: select for update row 2 <<<== will NOT block, the row isn't locked.
session1: commit; <<< session 2 blocked again, I say again, because it became unblocked on session1 and reblocked by session3...


Rating

  (21 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Thanks for reply

Andrew Max, October 08, 2006 - 3:59 pm UTC

>> try this to see what i mean about getting blocked on transactions
>> ...

Tom,
thanks a lot for your reply.

As for your example with savepoints - yes, there's a corresponding note in SQL reference which explains it:

"ROLLBACK TO SAVEPOINT
Releases all table and row locks acquired since the savepoint. Other transactions that have requested access to rows locked after the savepoint must continue to wait until the transaction is committed or rolled back. Other transactions that have not already requested the rows can request and access the rows immediately."

And I think I got your remark: "when you get blocked, you enqueue ON THE TRANSACTION itself".

But this seems to be the answer to my original question:

>> It doesn't see that one of them will eventually give up trying,
>> that information just isn't exposed, this will raise a deadlock. Period.

Let me rephrase it and please, correct me if I'm wrong:

It works just the way it works.
Timeout information is just unavailable to deadlock detection procedures.
ITL slots simply do not have such information.

Right???

Thanks and regards,
Andrew.

Tom Kyte
October 08, 2006 - 4:43 pm UTC

correct (sort if, even if the ITL slots had that.... it wouldn't matter) :) I like the "it works just the way it works" bit best of all ...

Alberto Dell'Era, October 08, 2006 - 5:21 pm UTC

This scenario shows another compelling reason for always closing TX on error:

DML statement(s)
if everything ok then
commit
else
rollback
end

I've noticed that most people (me including years ago) don't code the rollback branch when there's a single DML statement, the reasoning is "if the DML threw an error, db was not modified, so there's nothing to rollback". This seems intuitively obvious but it's wrong.

Tom Kyte
October 08, 2006 - 5:37 pm UTC

another compelling reason for the CLIENT APPLICATION, the only thing that can really control transaction flow, should either

a) commit or
b) rollback

its work. (along with triggers, autonomous transactions and when others, I would do away with commit and rollback in plsql if I had my way :)

Just to clarify

Andrew Max, October 08, 2006 - 7:55 pm UTC

>> sort of, even if the ITL slots had that.... it wouldn't matter

Sure, it wouldn't... :) sorry for confusing issue, just don't know why did I mention ITLs - well, maybe because sometimes "ITL deadlocks" may occur due to low values of INITRANS - but that's another story in any case.

"It works the way it works" because enqueue-related memory structures do not contain timeout information.
V$ENQUEUE_LOCK does not contain it.
And even fixed tables used internally by Oracle (X$KSQEQ, X$KSQRS) do not contain it.

Or am I lying again?



Hi Alberto,
I'm afraid I missed your point here:

>> I've noticed that most people (me including years ago) don't code the rollback branch when there's a single DML statement

I always thought that need of COMMIT/ROLLBACK is dictated solely by client app or some business-logic driven demands (plus some special cases like autonomous transactions mentioned by Tom).
What did you mean then?

Tom Kyte
October 09, 2006 - 8:20 am UTC

it works the way it works because we enqueue on Transactions, you are in fact only superficially waiting for a specific row, you went to that row, found it locked and started waiting on the transaction that held the lock. You stopped waiting for the row, you started waiting for the transaction.

So, even if we knew "row lock expires in 30 seconds", it wouldn't matter - you are not really waiting on the row, you are really waiting on the transction that once held the lock.

Alberto Dell'Era, October 09, 2006 - 8:35 am UTC

> Hi Alberto,
> I'm afraid I missed your point here:

It was meant to be pseudocode, not "pl/sql code in a stored procedure", as both you and Tom understood it :)

To clarify, here's that pseudocode incarnated in Java:

try {
... connection.prepareStatement ("update.../insert.../delete...");
// or, much better
... connection.preparecall ("begin storedProcedure ... end");

connection.commit();
}
catch (...) {
connection.rollback();
}

That will always close the transaction when an exception occurs, freeing (among other things) any other session that is waiting on your TX enqueue. That way the scenario described in this thread can't happen, since the ORA-30006 will trigger the rollback(), thus letting the other session continue.

I've noticed many times this fragment:
try {
// a single call:
... connection.preparecall ("begin storedProcedure ... end");

connection.commit();
} catch (...) {
// anything here, but not rollback() - WRONG
}

The developer's usual reasoning (apparently sound) is that there's no need to rollback, since any row modification made by the call has been rollbacked when the exception was raised - the reasoning is wrong, since the *statement* is rollbacked, but not the *transaction*.

Tom Kyte
October 09, 2006 - 9:01 am UTC

just to add fuel to the fire :)

it *might* have rolled back the transaction - depending on how many statements have been executed.


ops$tkyte%ORA9IR2> create table t ( x int );

Table created.

ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> create or replace procedure p( p_fail_point in number )
  2  as
  3  begin
  4          insert into t values ( 1 );
  5          if ( p_fail_point = 1 )
  6          then
  7                  raise program_error;
  8          end if;
  9  end;
 10  /

Procedure created.

ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> select count(*) from v$transaction;

  COUNT(*)
----------
         0

ops$tkyte%ORA9IR2> exec p(0)

PL/SQL procedure successfully completed.

ops$tkyte%ORA9IR2> select count(*) from v$transaction;

  COUNT(*)
----------
         1

<b>Success - we have transaction....</b>

ops$tkyte%ORA9IR2> commit;

Commit complete.

ops$tkyte%ORA9IR2> exec p(0);

PL/SQL procedure successfully completed.

ops$tkyte%ORA9IR2> exec p(1);
BEGIN p(1); END;

*
ERROR at line 1:
ORA-06501: PL/SQL: program error
ORA-06512: at "OPS$TKYTE.P", line 7
ORA-06512: at line 1


ops$tkyte%ORA9IR2> select count(*) from v$transaction;

  COUNT(*)
----------
         1

<b>Success followed by failure - we have tranaction</b>

ops$tkyte%ORA9IR2> commit;

Commit complete.

ops$tkyte%ORA9IR2> exec p(1);
BEGIN p(1); END;

*
ERROR at line 1:
ORA-06501: PL/SQL: program error
ORA-06512: at "OPS$TKYTE.P", line 7
ORA-06512: at line 1


ops$tkyte%ORA9IR2> select count(*) from v$transaction;

  COUNT(*)
----------
         0

ops$tkyte%ORA9IR2> commit;

Commit complete.

<b>start with failure, we have no transaction</b> 

Confused again

Andrew Max, October 09, 2006 - 9:59 am UTC

>> You stopped waiting for the row, you started waiting for the transaction ...

... Ok. And the fact that I started waiting with timeout just isn't exposed anywhere, right?

>> start with failure, we have no transaction

Tom, it seems to be kind of optimization trick, right? After all, we don't really need this transaction, its very first DML failed, we didn't do any job so new transaction would be just a waste of resources. Maybe, I'm mistaken of course...

Anyways, this one still keeps me wondering. Consider:

SQL> commit;

Commit complete.

SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         0

SQL> savepoint s1;

Savepoint created.

SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         0

SQL> exec p(1)
BEGIN p(1); END;

*
ERROR at line 1:
ORA-06501: PL/SQL: program error
ORA-06512: at "MAX.P", line 6
ORA-06512: at line 1


SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         1

SQL>

Or even "worse":

SQL> commit;

Commit complete.

SQL> savepoint s1;

Savepoint created.

SQL> rollback to s1;

Rollback complete.

SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         0

SQL> exec p(1)
BEGIN p(1); END;

*
ERROR at line 1:
ORA-06501: PL/SQL: program error
ORA-06512: at "MAX.P", line 6
ORA-06512: at line 1


SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         1

No ideas - I give up :) Could you please explain this behaviour?

Regards. 

Tom Kyte
October 09, 2006 - 10:19 am UTC

... And the fact that I started waiting with timeout just isn't exposed 
anywhere, right? ...

correct, but not "relevant".  You are waiting on a transaction now, even when that transaction "times out", you are still waiting, you do not become unblocked.



That failed "transaction" might have have thousands of SUCCESSFUL DMLS

ops$tkyte%ORA9IR2> create or replace procedure p( p_fail_point in number )
  2  as
  3  begin
  4          for i in 1 .. 2000
  5          loop
  6                  insert into t values ( 1 );
  7          end loop;
  8          if ( p_fail_point = 1 )
  9          then
 10                  raise program_error;
 11          end if;
 12  end;
 13  /

Procedure created.


That procedure has the same effect, it is because the first STATEMENT submitted by the client (the procedure call) fails - it is not a function of the number of successful dml statements.


Your explicit savepoint processing over shadowed the default one we do.


the logic is:

if you rollback to savepoint and nothing else tranactional has yet been done, we'll actually rollback the entire transction.


Your stored procedure call of:

exec p(1)

is really:

begin
savepoint internal_hidden_from_you;
p(1);
exception when others then
   rollback to internal_hidden_from_you;
   RAISE;
end;


If that savepoint internal_hidden_from_you is the first statement - the entire thing is rolled back.  When you did the savepoint/rollback to savepoint - it was no longer "the first statement" 

Confused a lot

Andrew Max, October 09, 2006 - 10:15 am UTC

Well, and here are some new findings:

SQL> commit;

Commit complete.

SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         0

SQL> select dbms_transaction.local_transaction_id from dual;

LOCAL_TRANSACTION_ID
-------------------------------------------------------------



SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         0

SQL> savepoint s1;

Savepoint created.

SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         0

SQL> select dbms_transaction.local_transaction_id from dual;

LOCAL_TRANSACTION_ID
-------------------------------------------------------------

2.14.98467

SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         1

SQL>

I'm really running out of ideas... what's going on behind the scenes???

Regards. 

Tom Kyte
October 09, 2006 - 10:26 am UTC

don't worry too much about it.

How about this:

all transactions must be terminated with either an explicit

a) commit
b) rollback

reliance on "default, observed behavior" is a bad idea for professional programmers in all languages. Be explicit, not implicit.


Basically, it is all dependent on the first transaction control statement you issue. The record in v$transaction will appear if and when we need it.

question on parallel slaves,

A reader, October 09, 2006 - 12:50 pm UTC

If I run an update statement in parallel, is there a possibility to have lock or a deadlock kind of situation among the parallel slaves?

What would be wait event in that kind of situation?

Thanks,

v$transaction

Andrew Max, October 10, 2006 - 7:23 am UTC

Tom,

I got your point about "over-shadowing the default savepoint", thanks.
No more questions about this.

However:

>> don't worry too much about it

Heh, well... I don't "worry" about it. Really I don't. Just trying to follow your principal motto "learn something new every day", and nothing else. So every time I observe things I can't explain - I just want to know WHAT is happening behind the scenes and HOW does this really work.

Ok, one more question (if you don't mind).

>> The record in v$transaction will appear if and when we need it.

Now as I recall I already asked myself similar questions months ago, and your latter statement about v$transaction just reminded me about it.

So how about this:
Record in v$transaction will appear as soon as transaction becomes ACTIVE. True?
Seems that the following simple experiment proves what I'm saying.

Let's create two helper views: the first one is the subset of V$SESSION and the second one is subset of x$ktcxb (I don't like to fiddle with X$-tables but this time I have no other choice).

SQL*Plus: Release 9.2.0.8.0 - Production on Tue Oct 10 13:34:34 2006

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

SQL> conn / as sysdba
Connected.
SQL>
SQL> create or replace view my_txn as
  2  select sid, taddr
  3    from v$session
  4   where sid = (select sid
  5                  from v$mystat
  6                 where rownum = 1);

View created.

SQL> create or replace view all_txn as
  2  select ktcxbxba taddr,
  3         decode(ktcxbsta, 0, 'IDLE',
  4                          1, 'COLLECTING',
  5                          2, 'PREPARED',
  6                          3, 'COMMITTED',
  7                          4, 'HEURISTIC ABORT',
  8                          5, 'HEURISTIC COMMIT',
  9                          6, 'HEURISTIC DAMAGE',
 10                          7, 'TIMEOUT',
 11                          9, 'INACTIVE',
 12                          10,'ACTIVE',
 13                'UNKNOWN') state
 14    from x$ktcxb;

View created.

SQL> create table test(x int);

Table created.

SQL> conn / as sysdba
Connected.
SQL>
SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         0

SQL> select * from my_txn;

       SID TADDR
---------- --------
        15

So far, we didn't do anything "transactional" so our TADDR column is empty. Now:

SQL> savepoint s1;

Savepoint created.

SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         0

SQL> select * from my_txn;

       SID TADDR
---------- --------
        15 6B30E81C

Well, v$transaction tells us that there are currently no transactions but we already have one in fact: transaction state object already exists for our session as evidenced by non-empty TADDR value.

And x$ktcxb tells that our transaction is currently in "IDLE" state:

SQL> select * from all_txn where taddr = '6B30E81C';

TADDR    STATE
-------- ----------------
6B30E81C IDLE

Ok, let's modify some data and check again:

SQL> insert into test values (1);

1 row created.

SQL> select * from all_txn where taddr = '6B30E81C';

TADDR    STATE
-------- ----------------
6B30E81C ACTIVE

SQL> select count(*) from v$transaction;

  COUNT(*)
----------
         1

We did modify db state, we generated some undo data, our transaction became ACTIVE and, finally, we can watch it in v$transaction.
True?

Thanks in advance and ... sorry. I understand I'm way off-topic here: my original question was about deadlocks.

Kind regards. 

Tom Kyte
October 10, 2006 - 8:23 am UTC

please don't do stuff as sysdba, sysdba is special, magic and different. things work differently for it (try set transaction read only; for example :)


but in short, "yes"

good thread on dead locks

A reader, October 10, 2006 - 9:22 am UTC


Good thread

Mark, October 10, 2006 - 11:21 am UTC

"(along with triggers, autonomous transactions and when others, I would do away with commit and rollback in plsql if I had my way :)"

Tom, I've seen you write several times that triggers should be done away with, but I've never stumbled across your reasoning. Could you please explain or provide a link to an explanation? Personally I find triggers very useful. Just recently I wrote a simple after update/insert trigger that updates a timestamp column. Not sure what could be wrong with that.

Sorry for getting a bit off topic, but this has been bugging me for a while. :)

Thanks,
Mark

Tom Kyte
October 10, 2006 - 8:00 pm UTC

because the correct and proper use of triggers (and the others) is far far far far and away over shadowed by "not smart" uses of them.

</code> http://asktom.oracle.com/Misc/classic-example-of-why-i-despise.html <code>

I'd rather give up the very very occasional "good use" of them, to protect us from the "not smart" over use and abuse of them.

triggers...

Mark, October 10, 2006 - 5:20 pm UTC

Found the answer to my own question - </code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:469621337269#45195818234738 <code>
Searching for "hate triggers" (with the quotes) did the trick.

Mark

Subhasis Gangopadhyay, December 19, 2006 - 3:32 am UTC

Hi Tom,

I haved faced a very confusing deadlock situation and can not figure out how this can happen.My oracle version is 10.2.0.1.But my problem is that I can not simulate the situation as I had to disable the trigger so that development team's work is unhampered.

I have a simple table mention below without any primary/unique constraint mentioned below.

CREATE TABLE CL_BAK
(
CHANGE_LOG_PK NUMBER NOT NULL,
TABLE_NA VARCHAR2(50 BYTE),
RPT_GRP_IND VARCHAR2(1 BYTE),
CHANGE_DT DATE,
PROPERTY_PK NUMBER,
TABLE_PK NUMBER,
ACTION VARCHAR2(1 BYTE),
EXTRA_INFO_1 NVARCHAR2(256),
EXTRA_INFO_2 NVARCHAR2(256),
EXTRA_INFO_3 NVARCHAR2(256),
EXTRA_INFO_4 NVARCHAR2(256),
EXTRA_INFO_5 NVARCHAR2(256)
);

I have a trigger on change_log table which is same structure as cl_bak table.Though change_log has primary key, I am only selecting from the table in the trigger.The trigger can fire concurrently from many sessions.

CREATE OR REPLACE TRIGGER cdb_beferror
BEFORE INSERT ON CHANGE_LOG
BEGIN

DELETE FROM CL_BAK;

INSERT INTO CL_BAK
SELECT * FROM CHANGE_LOG;

END;

Now, recently I faced many deadlock situations(ora-00060)
and my trace file read like this -

/opt/oracle/admin/mcdb/udump/mcdb_ora_25997.trc
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
ORACLE_HOME = /opt/oracle/10gR2
System name: Linux
Node name: CAL2DD05
Release: 2.6.11-1.1369_FC4smp
Version: #1 SMP Thu Jun 2 23:08:39 EDT 2005
Machine: i686
Instance name: MCDB
Redo thread mounted by this instance: 1
Oracle process number: 49
Unix process pid: 25997, image: oracleMCDB@CAL2DD05

*** 2006-12-18 20:37:37.138
*** SERVICE NAME:(SYS$USERS) 2006-12-18 20:37:37.062
*** SESSION ID:(128.4789) 2006-12-18 20:37:37.062
DEADLOCK DETECTED
[Transaction Deadlock]
Current SQL statement for this session:
DELETE FROM CL_BAK
----- PL/SQL Call Stack -----
object line object
handle number name
0x3ab26ebc 5 CDB.CDB_BEFERROR
The following deadlock is not an ORACLE error. It is a
deadlock due to user error in the design of an application
or from issuing incorrect ad-hoc SQL. The following
information may aid in determining the deadlock:
Deadlock graph:
---------Blocker(s)-------- ---------Waiter(s)---------
Resource Name process session holds waits process session holds waits
TX-00050019-00008737 49 128 X 74 71 X
TX-000c0014-00007aa3 74 71 X 49 128 X
session 128: DID 0001-0031-000627D6 session 71: DID 0001-004A-00024921
session 71: DID 0001-004A-00024921 session 128: DID 0001-0031-000627D6
Rows waited on:
Session 71: obj - rowid = 00045D18 - AABF0YAAEAAAHOQADx
(dictionary objn - 285976, file - 4, block - 29584, slot - 241)
Session 128: obj - rowid = 00045D18 - AABF0YAAEAAAHOzAD/
(dictionary objn - 285976, file - 4, block - 29619, slot - 255)
Information on the OTHER waiting sessions:
Session 71:
pid=74 serial=65309 audsid=4739391 user: 242/CDB
O/S info: user: 129592, term: , ospid: 1234, machine: CAL2DC14
program:
Current SQL Statement:
DELETE FROM CL_BAK
End of information on OTHER waiting sessions.
===================================================

Now my question is,

Both the sessions involved in deadlock showing the same sql "DELETE FROM CL_BAK".It is a blind delete statement without any 'where' clause.How deadlock situation can occur here.It is worth mentioning here that this DELETE statement is fired only from the trigger.I just can not visualise that how in this situation the same statement causes a transaction deadlock or am I missing something.I am keeping aside ITL deadlock here.

Like always, please help me to get out of this puzzle!!

Many Thanks
Subhasis

Tom Kyte
December 19, 2006 - 8:16 am UTC

before I even think about looking at this - WHAT IS THE POINT of that trigger?????


that logic hurts my head in a severe way. Why are you DOING that?

Subhasis Gangopadhyay, December 19, 2006 - 9:07 am UTC

Hi Tom,

I understand your point.But basiccaly the trigger is not part of the application....it is a temporary solution for trapping some record duplication problem(in test environment) in our application..so taking a snapshot(instead of running queries on main table) of the business table just before insert and comparing this after insert to trap when the event occured etc. and send a notification to us.

Basically we are taking snapshot of the business table just before insert.So for taking snapshot, we are deleting the old records from the backup table.The trigger is basically for debugging purpose, it is a temporary thing.

But my doubt is how the deadlock can be for same blind delete statement from the trigger or am I missing something!!!!

Waiting for your reply eagerly.

Thanks
Subhasis

Tom Kyte
December 19, 2006 - 10:13 am UTC

ok, say CL_BAK has a row in it. Database is "idle".


session 1: locks resource A. A is "something else"

session 2: inserts into change_log - this will delete from cl_bak

session 1: inserts into change_log - this will BLOCK on the delete from cl_bak

session 2: tries to gain access to resource A

deadlock - that is one example.



this seems like a really bad implementation here - there are all kinds of multi-user concurrency issues. YOU CANNOT DO INTEGRITY ENFORCEMENT IN YOUR APPLICATION - without using the LOCK TABLE command.

That would solve your dead lock issue (serialize on the table) probably but make you have zero concurrency.

Come up with a REAL solution to your problem - you and I both know that if you hack together some trigger, it'll become "production". It is a horrible idea.

Fix the real problem.

Subhasis Gangopadhyay, December 20, 2006 - 2:22 am UTC

Hi Tom,

First thanks for your reply.

To start with, I am not worried here with INTREGRITY ENFORCEMENT as this is just for testing(and the actual table is not reffered by or referring anybody..it is just a standalone table), we had no other choice for debugging.We also got hold of the real problem using the trigger and there was real issue in application.We also didn't had to use 'lock table' or using 'for update' as the change_log table only gets inserted from one place but it can be concurrent.No ther dml on table.

Now the situation you explained could have caused deadlock that is fine...but my real question is then how the same statement can come in the trace file as 'DEADLOCK CAUSING SQLS'.If I understood your reply properly, below is my simulation of the situation - 

session 1
SQL> update t2 set a=null;

6 rows updated.

session 2
SQL> delete from cl_bak;

25197 rows deleted.

session 1
SQL> update t2 set a=null; --hangs

6 rows updated.

session 2
SQL> update t2 set a=null;

Deadlock situation!!

The trace file contained - 

===============================================
*** 2006-12-20 12:06:01.062
DEADLOCK DETECTED
[Transaction Deadlock]
Current SQL statement for this session:
delete from cl_bak
The following deadlock is not an ORACLE error. It is a
deadlock due to user error in the design of an application
or from issuing incorrect ad-hoc SQL. The following
information may aid in determining the deadlock:
Deadlock graph:
                       ---------Blocker(s)--------  ---------Waiter(s)---------
Resource Name          process session holds waits  process session holds waits
TX-001e001c-00000013        84     210     X             29     151           X
TX-001d000e-00000008        29     151     X             84     210           X
session 210: DID 0001-0054-00017568    session 151: DID 0001-001D-000AD313
session 151: DID 0001-001D-000AD313    session 210: DID 0001-0054-00017568
Rows waited on:
Session 151: obj - rowid = 0005355F - AABTVfAAEAAATjsAAA
  (dictionary objn - 341343, file - 4, block - 80108, slot - 0)
Session 210: obj - rowid = 00045D18 - AABF0YAAEAAAxKOAD2
  (dictionary objn - 285976, file - 4, block - 201358, slot - 246)
Information on the OTHER waiting sessions:
Session 151:
  pid=29 serial=3801 audsid=4740202 user: 242/CDB
  O/S info: user: 136951, term: CAL2DD15, ospid: 3656:2476, machine: CTS\CAL2DD15
            program: sqlplusw.exe
  application name: SQL*Plus, hash value=3669949024
  Current SQL Statement:
  update t2 set a=null
End of information on OTHER waiting sessions.
===================================================

So trace file rightly have 'delete from cl_bak' for session 1 and 'update t2 set a=null' for session 2,which is fine for me.

But in my earlier posting of trigger, the statements for both sessions were same i.e. 'delete from cl_bak'.That is what confusing me.
Hopefull for your reply.

Thanks again
Subhasis 

Tom Kyte
December 20, 2006 - 8:15 am UTC

if you do not care about data integrity, what is the point then. what is your goal.

very confusing to say "trying to avoid duplicates" at the same time you say "don't care about integrity"

if "dont care" is true - fix is simple, trivial. stop doing this.


you have two sessions doing blind work against a table - deadlocks are pretty much going to be a "fact of life" for you here.

Your logic is "not really smart" in a multi-user situation, serialization is a FACT here. I won't really comment further, this is not something I would even begin to suggest doing. It provides no purpose even.

Subhasis Gangopadhyay, December 20, 2006 - 2:30 am UTC

Hi Tom,

In my previous posting, the deadlock situation I had simulated had a typing error.

So again writing what I did - 

session 1
SQL> update t2 set a=null;

6 rows updated.

session 2
SQL> delete from cl_bak;

25197 rows deleted.

session 1
SQL> delete from cl_bak; --hangs

session 2
SQL> update t2 set a=null;

Deadlock situation!!

Thanks
Subhasis 

Subhasis Gangopadhyay, December 22, 2006 - 1:48 am UTC

Ok Tom,

Thanks anyway for your reply.Just to conclude, I also aware of the NOT-TO-SMART approach of this but this was a situation driven case and I just wanted to take help from you to understand the simulation for the deadlock.Just to let you know regarding "DON'T CARE DATA INTRGETY" AND "TRYING TO AVOID DUPLICATE ROWS"(I know you didn't like that), it was completely bussiness-driven case to solve a particular problem...I meant DATA INTRGETY for the backup table and avoiding duplicate records was the actual bug for which the triggers were written.I am repeating that with these triggers, we successfully trapped the bug(where from the duplicate rows were coming) and droped the trigger after that.

Thanks for the help and understanding as you always do!!Hope to get in touch with you soon.

Subhasis

Need your advice..

brad, June 07, 2008 - 1:07 pm UTC


Need your expert advice on this situation...

We have a ETL situation where we have to load every 5 minutes during the day...

The source system will insert data in to a list of staging tables and a unique job id into a log_table that pertains to that insert every 5 minutes. The
job_id will also be inserted in to each staging table.

The ETL process will then grab the list of job_ids from log_table and processes the data from the staging tables...Once the data has been processed the
data that pertains to the job_ids will be deleted from the staging tables.This also happens every 5 minutes..

My concern is since the source system is inserting new data into the same tables and i am deleting the data from the same tables, do you see any issues with deadlocks or
locks situation(table level locks..)? We are not touching the same data though..DO you foresee any problems?




Tom Kyte
June 09, 2008 - 11:44 am UTC

Oracle is designed for concurrency.

You can insert and delete from the same table at the same time without locking.

ORA-06501: PL/SQL: program error, April 18, 2009 - 2:38 pm UTC

ORA-06501: PL/SQL: program error

Tom Kyte
April 21, 2009 - 12:15 pm UTC

sounds like you have a bug in your code, doesn't it.

audit trail deadlock

jula, December 08, 2009 - 4:13 am UTC

hi Tom!

I have such confusing deadlock. Few sessions running the same procedure with different input data concurrently. So they select and update the same tables.
There are no deadlocks related to user tables, but Oracle audit update deadlock. Why it happens?
How to avoid such deadlocks?

The trace file:

*** 2009-11-27 13:43:23.126
*** SESSION ID:(185.3) 2009-11-27 13:43:23.125
DEADLOCK DETECTED ( ORA-00060 )
The following deadlock is not an ORACLE error. It is a
deadlock due to user error in the design of an application
or from issuing incorrect ad-hoc SQL. The following
information may aid in determining the deadlock:
Deadlock graph:
---------Blocker(s)-------- ---------Waiter(s)---------
Resource Name process session holds waits process session holds waits
TX-0066000a-002f81dd 87 185 X 82 181 X
TX-00410001-00844c98 82 181 X 87 185 X
session 185: DID 0001-0057-00000080 session 181: DID 0001-0052-00000483
session 181: DID 0001-0052-00000483 session 185: DID 0001-0057-00000080
Rows waited on:
Session 181: obj - rowid = 00004C67 - AAAExyAEhAAEx+FAAa
(dictionary objn - 19559, file - 289, block - 1253253, slot - 26)
Session 185: obj - rowid = 00004C67 - AAAExyAEhAAEx+FAAe
(dictionary objn - 19559, file - 289, block - 1253253, slot - 30)
Information on the OTHER waiting sessions:
Session 181:
pid=82 serial=47 audsid=0 user: 0/SYS
O/S info: user: , term: , ospid: , machine:
program:
Current SQL Statement:
update sys.aud$ set ses$actions=merge$actions(ses$actions,:3), spare2=nvl(spare2,:4)
where sessionid=:1 and ses$tid=:2 and action#=103 and (priv$used=:5 or priv$used is null and :5 is null)
End of information on OTHER waiting sessions.
Current SQL statement for this session:
update sys.aud$ set ses$actions=merge$actions(ses$actions,:3), spare2=nvl(spare2,:4)
where sessionid=:1 and ses$tid=:2 and action#=103 and (priv$used=:5 or priv$used is null and :5 is null)


Thank you
Tom Kyte
December 10, 2009 - 11:09 am UTC

are you doing this through dbms_job/scheduler? If so, contact support and reference Bug 5897367

If not, supply more information - things like version, platform, and an overview of what you are auditing and what the processes are doing.

audit trail deadlock

jula, December 11, 2009 - 2:08 am UTC

Yes, this is done through dbms_job. Thanks for help.

Question about deadlock

Apr, February 08, 2021 - 5:34 pm UTC

Hi,

If we catch the Ora 60 error in exception handler of the block which gave the deadlock error and retry the transaction ..will it work ?

IF one of the session itself gets killed by oracle - the connection to that session will be lost - right ? In that case will it ever go to the exception handler - so that the transaction can be retried ?

thanks
Chris Saxon
February 09, 2021 - 9:42 am UTC

Oracle Database resolves deadlocks by rolling back one of the statements; it doesn't kill the session.

So you can catch ORA-60 and retry the transaction. Whether retrying works depends on the application logic and why you hit deadlock in the first place!

It's possible you'll hit another deadlock or run into data issues due to lost updates. To know if it's safe to retry the transaction, you need to understand why you had deadlock in the first place.