问题描述:
系统业务繁忙时(特别是周一或周五),Oracle数据库出现死锁现象,造成数据库挂起,业务中断。
问题定位
首先分析数据库后台日志alert_raca1.log,alert_raca2.log,发现数据库死锁信息:
Global Enqueue Services Deadlock detected. More info in file
/oracle/admin/raca/bdump/raca1_lmd0_807258.trc.
Fri Mar 12 14:55:15 2010
Global Enqueue Services Deadlock detected. More info in file
/oracle/admin/raca/bdump/raca1_lmd0_807258.trc …
找到相应的trace文件中的信息进行分析:
user session for deadlock lock 70000020a0d60a0 pid=138 serial=70 audsid=14754928 user: 49/GFCOB O/S info: user: , term: , ospid: 1234, machine: GF14 program: Current SQL Statement:
update WF_TASKINFO set processInfoId=:1, taskInstanceId=:2, nodeId=:3, taskName=:4, taskDescription=:5, status=:6, startDate=:7,
handleGroup=:8, handleBy=:9, createdDate=:10, endedGroup=:11, endedBy=:12, endedDate=:13, expectedEndDate=:14, ownerType=:15, lockedBy=:16, lockedDate=:17, priority=:18, nodeType=:19, isBacked=:20, isCopied=:21, isSuspended=:22, tokenId=:23, extendField=:24, lastTaskInfoId=:25 where taskInfoId=:26 user session for deadlock lock 70000020a0d5f50 pid=246 serial=77 audsid=14754935 user: 49/GFCOB O/S info: user: , term: , ospid: 1234, machine: GF14 program: Current SQL Statement:
update HIS_GDB_B_BUSINESSISSUE set operateId=:1, taskInfoId=:2, handleGroup=:3, handleBy=:4, createdDate=:5, endedDate=:6,
endedType=:7, reply=:8, remark=:9 where orderHandleHistoryId=:10 找到造成死锁的sql语句后和业务开发人员进行分析,排除了队列死锁和位图索引死锁;
deadlock的dump信息;
BLOCKED 70000020a0d60a0 5 wq 2 cvtops x1 [0x234000e][0x1c6],[TX] [2008-008A-00000377] 1
BLOCKER 70000020a0d5f50 5 wq 1 cvtops x8 [0x234000e][0x1c6],[TX] [200F-00F6-00000EAC] 1
BLOCKED 70000020a0d7330 5 wq 2 cvtops x1 [0x153002a][0x2932],[TX] [200F-00F6-00000EAC] 1
BLOCKER 70000020b62dba8 5 wq 1 cvtops x8 [0x153002a][0x2932],[TX] [2008-008A-00000377] 1
排查后,问题确定为是由ITL事务槽数过少且不能自动扩展造成的死锁: 业务表的建表语句: -- Create table
create table WF_TASKINFO (
TASKINFOID VARCHAR2(36) not null, PROCESSINFOID VARCHAR2(36), TASKINSTANCEID NUMBER(19), ……… )
tablespace GDB1 pctfree 10 initrans 1 maxtrans 255
问题分析
数据库出现死锁是由于业务表初始事务槽(ITL)个数分配太少,无法动态扩展造成的。
ITL(Interested Transaction List)是Oracle数据块内部的一个组成部分,用来记录该块所有发生的事务,一个itl可以看作是一个记录,在一个时间,可以记录一个事务(包括提 交或者未提交事务)。
如果一个事务一直没有提交,那么,这个事务将一直占用一个itl槽位,itl
里面记录了事务信息,回滚段的入口,事务类型等等。如果这个事务已经 提交,那么,itl槽位中还保存的有这个事务提交时候的SCN号
对于已经提交的事务,itl槽位最好不要马上被覆盖,因为一致性读可能会用到这个信息,一致性读的时候,可能需要从这里获得回滚段的入口,并从回 滚段中获得一致性读。
itl的个数,受参数initrans控制,最大的itl个数,受maxtrans控制,在一个块内部,默认分配了2个或3个itl的个数,如果 这个块内还有空闲空间,那么Oracle是可以利用这些空闲空间并再分配itl的。如果没有了空闲空间,那么,这个块因为不能分配新的itl,所以就可能 发生itl等待。
如果在并发量特别大的系统中,最好分配足够的itl个数 ,或者设置足够的pctfree,保证itl能扩展,但是 pctfree有可能是被行数据给消耗掉的,如update,所以,也有可能导致块内部的空间不够而导致itl等待。
解决方案与步骤
通过调整业务表的初始事务槽个数消除业务忙时由事务槽竞争造成的数据库死锁:
1. 调整业务表的初始事务槽参数:
alter table WF_TASKINFO initrans 64; ………
2. 调整业务表pctfree参数(可选):
alter table WF_TASKINFO pctfree 20; 3. 将业务表move到其他的表空间:
alter table WF_TASKINFO move tablespace new_tbs; 4. 调整完成,检查业务是否正常
相关推荐: