Anda di halaman 1dari 6

DeadLock on adding foreign key constraint with DDL_LOCK_TIMEOUT

I was investigating a deadlock occurred in database version 11.2.0.3 when adding a foreign key constraint to a table with ddl_lock_timeout set. This is an excerpt of the deadlock trace and I have changed the tables name: Deadlock graph: ---------Blocker(s)-------- ---------Waiter(s)--------Resource Name process session holds waits process session holds waits TM-0000347c-00000000 313 120 S 388 411 SX TM-0000347c-00000000 388 411 SX 313 120 S session 120: DID 0001-0139-00006F61 session 411: DID 0001-0184-00006370 session 411: DID 0001-0184-00006370 session 120: DID 0001-0139-00006F61 Rows waited on: Session 120: no row Session 411: obj - rowid = 0000347C - AAAAAAAAAAAAAAAAAA (dictionary objn - 13436, file - 0, block - 0, slot - 0) ----- Information for the OTHER waiting sessions ----Session 411: ...... application name: JDBC Thin Client, hash value=2546894660 current SQL: INSERT INTO T2 (c1, c2) VALUES(:B1 , SYSDATE) ----- End of information for the OTHER waiting sessions ----Information for THIS session: ----- Current SQL Statement for this session (sql_id=4t89wsuvkswmx) ----LOCK TABLE "T1","T3" IN SHARE MODE WAIT 600 =================================================== Looking at the deadlock graph, session 120 was waiting for TM share and not actually holding any resource. This is an unusual deadlock scenario. What sequence of events could cause this type of deadlock? Here is the test case to reproduce the same deadlock graph when adding a foreign key constraint to a table: William Tang 2014-03-27 Page 1

Database version 11.2.0.3. create table parent (p1 number primary key); create table child1 ( c1 number not null, c2 number, CONSTRAINT child1_pk_c1_c2 PRIMARY KEY (c1, c2) using index enable, constraint child1_fk_p1 foreign key (c1) references parent(p1) enable ); create table child2 ( c1 number not null, c2 number, CONSTRAINT child2_pk_c1_c2 PRIMARY KEY (c1, c2) using index enable, constraint child2_fk_p1 foreign key (c1) references parent(p1) enable ); insert into parent select rownum from user_objects; insert into child1 select p1, rownum from parent; insert into child2 select p1, rownum from parent; commit; grant all on parent to public; grant all on child1 to public; grant all on child2 to public; --Create autonomous procedure CREATE OR REPLACE PROCEDURE insert_child2 is PRAGMA AUTONOMOUS_TRANSACTION; begin insert into child2(c1, c2) values(1, 2); commit; end; William Tang 2014-03-27 Page 2

/ exit ======================== SESSION 1: login as william(objects owner) SQL> select sys_context('userenv', 'sid') from dual; SYS_CONTEXT('USERENV','SID') -------------------------------------------------------------------------------1722 SESSION 2: login as sys SQL> select sys_context('userenv', 'sid') from dual; SYS_CONTEXT('USERENV','SID') -------------------------------------------------------------------------------21 ======================== STEP 1: Session 1 user william insert into william.child1 values (1, 2); 1 row created. query v$lock from session 3: SID 1722 with lmode TM 3 on parent(416154) SID TYPE ID1 ID2 LMODE REQUEST BLOCK 1722 AE 362856 0 4 0 0 1722 TM 416154 0 3 0 0 1722 TM 416156 0 3 0 0 1722 TX 524321 59122 6 0 0 21 AE 362856 0 4 0 0 ======================== STEP 2: Session 2 user sys create a new table and add foreign key constraint references parent table.

William Tang 2014-03-27

Page 3

create table william.child3 ( c1 number not null, c2 number, CONSTRAINT child3_pk_c1_c2 PRIMARY KEY (c1, c2) using index enable ); Table created. ALTER SESSION SET ddl_lock_timeout=600; Session altered. alter table william.child3 add constraint child3_fk_p1 foreign key (c1) references william.parent(p1) enable; Session 2 is now requesting TM 4 and waiting for session 1 to commit/rollback. v$lock shows session 1 (sid=1722) holds parent table in TM 3 and session 2 (sid=21) requests TM 4. SID TYPE ID1 ID2 LMODE REQUEST BLOCK 1722 AE 362856 0 4 0 0 1722 TM 416154 0 3 0 1 1722 TM 416156 0 3 0 0 1722 TX 524321 59122 6 0 0 21 TM 416154 0 0 4 0 21 AE 362856 0 4 0 0 query dba_objects from session 3 to see object ID. OWNER OBJECT_NAME OBJECT_ID DATA_OBJECT_ID WILLIAM PARENT 416154 416154 WILLIAM CHILD1 416156 416156 WILLIAM CHILD2 416158 416158 WILLIAM CHILD3 416160 416160 ======================== STEP 3: Session 1 user william exec insert_child2; ---- autonomous procedure Session 1 autonomous procedure insert_child2 will request TM 3 on parent table, but session 2 already requested TM 4 first. So session 1 autonomous procedure will wait for session 2, but session 2 is waiting for session 1 to commit/rollback. We have a deadlock. SESSION 2 detected the deadlock

William Tang 2014-03-27

Page 4

SQL> alter table william.child3 add constraint child3_fk_p1 foreign key (c1) references william.parent(p1) enable; alter table william.child3 add constraint child3_fk_p1 foreign key (c1) references william.parent(p1) enable * ERROR at line 1: ORA-00060: deadlock detected while waiting for resource And SESSION 1 completed the autonomous procedure call. SQL> exec insert_child2; PL/SQL procedure successfully completed. ======================== Here is dealock graph of test case: Deadlock graph: ---------Blocker(s)-------- ---------Waiter(s)--------Resource Name process session holds waits process session holds waits TM-0006599a-00000000 52 21 S 51 1722 SX TM-0006599a-00000000 51 1722 SX 52 21 S session 21: DID 0001-0034-00000019 session 1722: DID 0001-0033-0000011D session 1722: DID 0001-0033-0000011D session 21: DID 0001-0034-00000019 Rows waited on: Session 21: no row Session 1722: obj - rowid = 0006599A - AAAAAAAAAAAAAAAAAA (dictionary objn - 416154, file - 0, block - 0, slot - 0) ----- Information for the OTHER waiting sessions ----Session 1722: sid: 1722 ser: 285 audsid: 28773729 user: 252/WILLIAM flags: (0x41) USR/- flags_idl: (0x1) BSY/-/-/-/-/flags2: (0x40009) -/-/INC pid: 51 O/S info: user: oracle, term: UNKNOWN, ospid: 32469 image: oracle@dba6 (TNS V1-V3) client details: O/S info: user: oracle, term: pts/2, ospid: 32468 machine: dba6 program: sqlplus@dba6 (TNS V1-V3) application name: SQL*Plus, hash value=3669949024 current SQL: William Tang 2014-03-27 Page 5

INSERT INTO CHILD2(C1, C2) VALUES(1, 2) ----- End of information for the OTHER waiting sessions ----Information for THIS session: ----- Current SQL Statement for this session (sql_id=87805s230jvg8) ----LOCK TABLE "WILLIAM"."CHILD3","WILLIAM"."PARENT" IN SHARE MODE WAIT 600 =================================================== With the same test case tested in 10.2.0.4, this deadlock scenario did not occur because lock mode is different in 10.2.0.4. If I don't set DDL_LOCK_TIMEOUT in 11g, adding FK constraint session will get ORA-00054 and no deadlock will occur. For Oracle version 10.2.0.4, when insert into child table, Oracle will lock parent table in TM 2(which is compatible to FK constraint requests of TM 4). For version 11.2.0.3 and 12.1, lock mode for parent table is TM 3. The lock mode change is not a bug according to Oracle documents. Documents from Oracle support: Bug 5909305 - Change to DML (TM) lock modes for foreign key constraints (Doc ID 5909305.8) Bug 7015340 : FK WITH INDEX CAUSES ROW-EXCLUSIVE INSTEAD OF SUBSHARE TABLE LOCK - DOC BUG Bug 14350611 - SX lock acquired for foreign key when SS should do (Doc ID 14350611.8) Bug 5909305 - Change to DML (TM) lock modes for foreign key constraints (Doc ID 5909305.8) Bug 8881121 : CHANGE TO DML LOCK MODES FOR FOREIGN KEY CONSTRAINTS References: http://arup.blogspot.com/2013/04/application-design-is-only-reason-for.html http://hoopercharles.wordpress.com/2010/01/07/deadlock-on-oracle-11g-but-not-on-10g/ http://jonathanlewis.wordpress.com/2010/02/15/lock-horror/

William Tang 2014-03-27

Page 6

Anda mungkin juga menyukai