DBINST started to display the following error message:

ORA-00060: Deadlock detected. More info in file /u01/app/oracle/admin/DBINST/udump/DBINST_ora_1705.trc.

When the deadlocks occurred, the application was failing and logging errors too.

Oracle Concept Manual: “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. … Oracle automatically detects deadlock situations and resolves them by rolling back one of the statements involved in the deadlock, thereby releasing one set of the conflicting row locks.

The start of the trace files were similar to each other, so it appeared to be the same piece of code causing the problem:

DEADLOCK DETECTED
Current SQL statement for this session:
delete from PORTDETAIL where ID=:1 and version=:2
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
TM-0000e7bc-00000000        28     132    SX   SSX       25     135    SX   SSX
TM-0000e7bc-00000000        25     135    SX   SSX       28     132    SX   SSX
session 132: DID 0001-001C-0000052F     session 135: DID 0001-0019-00000B29
session 135: DID 0001-0019-00000B29     session 132: DID 0001-001C-0000052F
Rows waited on:
Session 135: obj - rowid = 0000E7DC - AAAOfcAAFAAAAjIAAA
(dictionary objn - 59356, file - 5, block - 2248, slot - 0)
Session 132: obj - rowid = 0000E7DC - AAAOfcAAFAAAAjIAAA
(dictionary objn - 59356, file - 5, block - 2248, slot - 0)
Information on the OTHER waiting sessions:
Session 135:
pid=25 serial=1301 audsid=134658 user: 60/EGSCHEMA
O/S info: user: , term: , ospid: 1234, machine: dbserver.local
program:
Current SQL Statement:
delete from PORTDETAIL where ID=:1 and version=:2
End of information on OTHER waiting sessions.

I looked noticed that this was a bit different than other deadlocks I’ve seen; it was dead locking on table locks instead of row locks (transactions). This made me suspect a foreign key wasn’t indexed. (It could be the result of an application doing something unusual, like issuing lock table commands or DDL even).

So in this case we should ignore the “Rows waited on” section, which is useful when we have blocking transactions (TX).

I checked which table was locked:

TM=table lock (DML lock)
0x0000e7bc=59324

select owner, object_name from dba_objects where DATA_OBJECT_ID=59324;
OWNER
------------------------------
OBJECT_NAME
------------------------------
EGSCHEMA
PORTSERVICEORDER

Note that this isn’t the table in the SQL statement for either session: PORTDETAIL.

So, is there a trigger or a foreign key that could cause a lock on PORTSERVICEORDER when a row from PORTDETAIL is deleted?

@dd
EGSCHEMA
PORTDETAIL
TYPE              NAME                           OWNER                          'SOF 'REFERENCED'  NULL
----------------- ------------------------------ ------------------------------ ---- ------------- ------------------------------
INDEX             PD_PSO_IDX                     EGSCHEMA                       HARD ON_OBJECT
INDEX             PK_PORTDETAIL                  EGSCHEMA                       HARD ON_OBJECT
TABLE             PORTITEM                       EGSCHEMA                       HARD FK_REF_OBJECT FK_PORTITEM_PORTDETAIL
TABLE             PORTSERVICEORDER               EGSCHEMA                       HARD FK_REF_OBJECT FK_PSO_APPROVEDPORTDETAILS
TABLE             PORTSERVICEORDER               EGSCHEMA                       HARD FK_REF_OBJECT FK_PSO_GSPPORTDETAILS
VIEW              VIEW_GC_LC_FOR_COMPLETED_PORTS EGSCHEMA                       SOFT REFERENCED

Yes! Two foreign keys.

Are these foreign keys indexed?

@$DBA_SQLPATH/apt/missing_fk_indexes.sql
TABLE_NAME                                       COLUMN_NAME
------------------------------------------------ ------------------------------
EGSCHEMA.PORTSERVICEORDER                        APPROVEDPORTDETAILS
EGSCHEMA.PORTSERVICEORDER                        GSPPORTDETAILS

No, neither of them are indexed.

My Interpretation

A row is being updated or deleted from the child PORTSERVICEORDER, and then a row is deleted from the parent table PORTDETAIL in the same transaction. There is no index on the foreign key so a lock is taken on the whole PORTSERVICEORDER table. When two sessions attempt these same steps concurrently, they would deadlock because they both hold an SX (row exclusive) lock in PORTSERVICEORDER and both are asking for an SSX (share sub-exclusive) lock on PORTSERVICEORDER.

In general, foreign keys should be indexed unless the parent table has very little DML on it. So… I asked the developers to index these foreign keys and we haven’t had deadlocks since.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s