测试库死锁诊断DEADLOCK DETECTED ( ORA-00060 )

 

20125月份的一天,开发同事找到我,说测试库碰到了死锁问题,要求帮忙看看。

1.死锁问题及建议

死锁:DEADLOCK DETECTED ( ORA-00060 )

现象

Thu May 17 10:35:35 2012

ORA-00060: Deadlock detected. More info in file /oradata/diag/rdbms/orcl/orcl/trace/orcl_ora_893044.trc.

trace文件信息摘录

*** 2012-05-17 10:35:34.727

DEADLOCK DETECTED ( ORA-00060 )

 

[Transaction Deadlock]

 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-0001226e-00000000       118     371    SX   SSX      117     310    SX   SSX

TM-0001226e-00000000       117     310    SX   SSX      118     371    SX   SSX

 

session 371: DID 0001-0076-00000002     session 310: DID 0001-0075-00000008

session 310: DID 0001-0075-00000008     session 371: DID 0001-0076-00000002

 

Rows waited on:

  Session 371: no row

  Session 310: no row

 

----- Information for the OTHER waiting sessions -----

Session 310:

  sid: 310 ser: 88 audsid: 2818451 user: 102/DATAMGR flags: 0x100045

  pid: 117 O/S info: user: oracle, term: UNKNOWN, ospid: 1212508

    image: oracle@localhost

  client details:

    O/S info: user: bisp, term: unknown, ospid: 1234

    machine: dmsvr.bisp program: JDBC Thin Client

    application name: JDBC Thin Client, hash value=2546894660

  current SQL:

  DELETE FROM FORECAST_KEYPOINT WHERE FORECAST_ID = :1

 

----- End of information for the OTHER waiting sessions -----

 

Information for THIS session:

 

----- Current SQL Statement for this session (sql_id=0jdjc3kdu7dnz) -----

DELETE FROM FORECAST_KEYPOINT WHERE FORECAST_ID = :1

****************************************************************************

Session371session310发起的两个事务分别包含上述标红的sql语句相互等待对方资源的释放造成死锁

首先注意到的是Deadlock graph中的资源占有情况,可以看到两个session都hold了一个SX类型的锁,同时在等待SSX类型的锁,而且引发的是一个删除语句,并且这个表是系统的一个关键表,大部分的表的外键都引用自此表的主键。因此猜测是碰到了外键引发的死锁。

建议1:

应用程序开发人员检查表FORECAST_AIRPORT和表FORECAST_KEYPOINT之间的关系(如父表FORECAST_KEYPOINT、子表FORECAST_AIRPORT  具体参照哪一列),有哪些约束、索引等;

如果子表上的外键约束列没有建立索引,删除父表记录时不得不对子表加表级锁,防止其他删除操作对该表的操作,要解决这种死锁问题则需要在子表的外键约束裂伤建立相应的索引;

这样,当对子表的外键列添加索引后,死锁可以被消除,因为这时删除父表记录不需要对子表加表级锁。   (后面有模拟实验可以验证)

创建索引:create index index_name on schema.table_name(column_name);

create index index_name on pdmcompard.FORECAST_AIRPORT (FORECAST_ID);

create index index_name on datamgr.FORECAST_AIRPORT (FORECAST_ID);

建议2

也有可能是循环删除的问题(如果第1个建议没有成功,可以试试此方法)
如果可以,改成delete from t_user where ID in (:1,:2...)

《调整业务逻辑,修改应用程序,合理分配资源》

2.附录及实验

1 OracleTM锁类型
锁模式        锁描述        解释        SQL操作
0        none                  
1        NULL       
        Select
2        SS(Row-S)       
行级共享锁,其他对象只能查询这些数据行        Select for updateLock for updateLock row share
3        SX(Row-X)       
行级排它锁,在提交前不允许做DML操作        InsertUpdateDeleteLock row share
4        S(Share)       
共享锁        Create indexLock share
5        SSX(S/Row-X)       
共享行级排它锁        Lock share row exclusive
6        X(Exclusive)       
排它锁        Alter tableDrop ableDrop indexTruncate table Lock exclusive

试验如下:
1
、创建一个表,此表作为子表
SQL> create table fk_table as select * from user_objects;

Table created
2
、创建一个表,此表作为父表
SQL> create table pk_table as select * from user_objects;

Table created
3
、创建父表的主键
SQL> alter table PK_TABLE add constraint pk_pktable primary key (OBJECT_ID);

Table altered
4
、创建子表的外键
SQL> alter table FK_TABLE add constraint fk_fktable foreign key (OBJECT_ID) references pk_table (OBJECT_ID);

Table altered
5
、如下sql取自TOAD工具,用来显示数据库锁的信息
SELECT LK.SID,
SE.USERNAME,
SE.OSUSER,
SE.MACHINE,
DECODE(LK.TYPE,
'TX',
'Transaction',
'TM',
'DML',
'UL',
'PL/SQL User Lock',
LK.TYPE) LOCK_TYPE,
DECODE(LK.LMODE,
0,
'None',
1,
'Null',
2,
'Row-S (SS)',
3,
'Row-X (SX)',
4,
'Share',
5,
'S/Row-X (SSX)',
6,
'Exclusive',
TO_CHAR(LK.LMODE)) MODE_HELD,
DECODE(LK.REQUEST,
0,
'None',
1,
'Null',
2,
'Row-S (SS)',
3,
'Row-X (SX)',
4,
'Share',
5,
'S/Row-X (SSX)',
6,
'Exclusive',
TO_CHAR(LK.REQUEST)) MODE_REQUESTED,
TO_CHAR(LK.ID1) LOCK_ID1,
TO_CHAR(LK.ID2) LOCK_ID2,
OB.OWNER,
OB.OBJECT_TYPE,
OB.OBJECT_NAME,
LK.BLOCK,
SE.LOCKWAIT
FROM V$LOCK LK, DBA_OBJECTS OB, V$SESSION SE
WHERE LK.TYPE IN ('TM', 'UL')
AND LK.SID = SE.SID
AND LK.ID1 = OB.OBJECT_ID(+);

6
、执行一个删除操作,这时候在子表和父表上都加了一个Row-S(SX)
delete from fk_table where object_id=94716;
delete from pk_table where object_id=94716;
7
、执行另一个删除操作,发现这时候第二个删除语句等待
delete from fk_table where object_id=94702;
delete from pk_table where object_id=94702;
执行查询语句,得到锁信息如下:
857 DML Row-S (SS) None 107220 0
BILL TABLE PK_TABLE 0 00000000D555A0E8
872 DML Row-X (SX) None 107220 0 BILL TABLE PK_TABLE 0
857 DML Row-X (SX) S/Row-X (SSX) 107219 0 BILL TABLE FK_TABLE 0 00000000D555A0E8
872 DML Row-X (SX) None 107219 0 BILL TABLE FK_TABLE 1
可以看到session 857在请求一个SSX类型的锁,此时如果执行如下操作:
delete from pk_table where object_id=94716;
死锁马上发生,因为857 SESSION拿到了一个对FK_TABLE的行独占锁,并在请求一个表共享锁,而872 SESSION也拿到了一个FK_TABLE上的行独占锁,并请求一个表共享锁。此时两个session谁都不会释放独占锁,并同时请求表的共享锁,死锁由此引发。因为死锁引发的时候两个session不是在等待对数据行进行加锁,所以可以从trace文件中发现等待的行都为no row,同时可以看到两个sessionhold了一个SX锁,并且都在等待SSX锁资源。同时trace文件中还记录了引发死锁的sql

Deadlock graph:
---------Blocker(s)-------- ---------Waiter(s)---------
Resource Name process session holds waits process session holds waits
TM-0001a2d3-00000000 16 872 SX SSX 20 857 SX SSX
TM-0001a2d3-00000000 20 857 SX SSX 16 872 SX SSX
session 872: DID 0001-0010-000F5EA0 session 857: DID 0001-0014-001D7407
session 857: DID 0001-0014-001D7407 session 872: DID 0001-0010-000F5EA0
Rows waited on:
Session 857: no row
Session 872: no row

Current SQL Statement:
delete from pk_table where object_id=94716
8
、当对子表的外键列添加索引后,死锁被消除,因为这时删除父表记录不需要对子表加表级锁,这里不再做测试。

结论:曾经有人讨论过是否所有的数据库设计都应该遵守范式的规范,都把主外键关系建立起来。也有人反对这样做,因为这样复杂的关系在OLTP系统中可能会成为灾难,而提倡通过程序来保证数据的完整性,但程序发生bug导致数据不一致的情况时有发生。而且如果外键设置为级联删除,则不加索引的外键会使得对子表的记录删除走全表扫描。因此,对外键的使用还是要慎重!

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/21256317/viewspace-1062001/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/21256317/viewspace-1062001/

ORA-00060: deadlock detectedOracle数据中的一个错误代码,它表示在等待资源时检测到了死锁死锁是指两个或多个进程相互等待对方所持有的资源,导致系统无法继续进行下去。 这个错误通常与并发操作有关,其中至少有两个会话(或进程)试图同时访问相同的资源,但由于彼此之间的依赖关系,她们无法继续执行下去。 根据引用中的描述,当会话1执行UPDATE语句时,尝试更新id为2的记录,但同时会话2也在等待并尝试更新id为1的记录。由于两个会话互相依赖,并且需要等待对方释放资源,因此发生了死锁,导致其中一个会话被自动终止,并抛出ORA-00060错误。 要解决ORA-00060错误,可以采取以下措施: 1. 观察和记录死锁事件的发生情况。可以使用Oracle提供的性能监视工具,如AWR报告或ADDM报告,来分析和识别频繁发生死锁的模式和原因。 2. 优化数据设计和应用程序逻辑。检查数据表和索引的设计,确保它们能够最小化并发操作引发死锁的可能性。同时,应用程序逻辑也需要考虑到并发访问资源的情况,避免出现相互依赖导致的死锁。 3. 使用适当的并发控制机制。可以使用Oracle提供的锁机制,如行级锁或表级锁,来管理并发操作。合理选择锁的粒度,避免不必要的锁竞争,减少死锁的概率。 4. 在发生死锁时,可以通过修改会话的事务隔离级别来解决问题。例如,将事务隔离级别设置为READ COMMITTED,以减少锁的范围,降低死锁风险。 总之,ORA-00060: deadlock detectedOracle数据中一个常见的错误代码,表示在并发操作中检测到了死锁。通过观察和记录死锁事件,优化数据设计和应用程序逻辑,以及使用适当的并发控制机制,可以减少死锁的发生概率,并提高系统的性能和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值