死事务,一般是事务正在跑的时候,被kill掉了,或者数据库shutdown abort了,那么当数据库再次启动的时候,这些事务就需要做回滚。
可以通过下面的语句查到回滚的事务:
1 2 3 |
select * from v$fast_start_transactions; 或者 select * from x$ktuxe where KTUXECFL='DEAD' AND KTUXESTA!='INACTIVE' |
根据上面的语句,我们可以查到事务的undo的segment id(USN或者KTUXEUSN),undo的slot(SLT或者KTUXESLT),和undo的sequence(SEQ或者KTUXESQN)。
根据USN,我们可以查到undo segment:
1 |
select * from v$rollname where usn=xxx |
根据上面的语句,我们可以dump出undo block:
1 2 3 |
alter system dump undo block "<undo segment name>" XID <USN> <SLT> <SEQ>; 如 alter system dump undo block "_SYSSMU33$" XID 33 56 7463; |
然后根据dump出来的trace file,可以判断object number(objn)或者object id(objd)
1 2 3 4 5 6 7 8 9 |
cat xxx.trc |grep objn * Rec #0x45 slt:0x1f objn:601130(0x00092c2a) objd:601130 tblspc:20(0x00000014) * Rec #0x44 slt:0x1f objn:601130(0x00092c2a) objd:601130 tblspc:20(0x00000014) * Rec #0x43 slt:0x1f objn:601130(0x00092c2a) objd:601130 tblspc:20(0x00000014) * Rec #0x42 slt:0x1f objn:601130(0x00092c2a) objd:601130 tblspc:20(0x00000014) * Rec #0x41 slt:0x1f objn:601130(0x00092c2a) objd:601130 tblspc:20(0x00000014) * Rec #0x40 slt:0x1f objn:601130(0x00092c2a) objd:601130 tblspc:20(0x00000014) * Rec #0x3f slt:0x1f objn:601130(0x00092c2a) objd:601130 tblspc:20(0x00000014) ... |
此时,我们根据object id,可以在数据库里面找到回滚的object的对象:
1 |
select * from dba_objects where object_id='601130'; |
此时,如果你select count(*) from 这个表,你会发现在回滚完前,这个很简单的select操作会一直处于”db file sequential read”的等待,而且对应的p1是file file,是undo 表空间的数据文件。
我们继续,要查回滚死事务的时间,可以利用x$ktuxe,注意看其单位时间内减少了多少KTUXESIZ,即减少了多少个undo block。根据这个速度,可以估算回滚速度。注,这个速度只是大概的,有时候往往会非线性的减少。
加快回滚速度,我们需要用到一个参数fast_start_parallel_rollback,这个参数默认是low,即2倍cpu数的并发度,进行并发的回滚。我们可以设置成high,即为4倍cpu数的并发度进行回滚。
而high的时候,有时会用去比较多的资源,特别是cpu资源,会看到很多并发进程ora_pnnn,同时去查v$px_session的话,会发现他们的qcsid是smon的进程。在很高的并发度下,会影响生产的稳定,有时甚至撑爆了process数导致应用无法连接,因此需要特别的注意。我们对fast_start_parallel_rollback进行调整,可以调整成low甚至false。
而并发度如果是high或low,4倍或2倍的cpu数,也会受到另外一些参数的影响,如PARALLEL_MAX_SERVERS,这个才是真正最大的并发度设置。
PARALLEL_MAX_SERVERS这个参数的默认值为PARALLEL_THREADS_PER_CPU * CPU_COUNT * concurrent_parallel_users * 5。PARALLEL_THREADS_PER_CPU 和CPU_COUNT都是初始化参数。concurrent_parallel_users 根据是否启用automatic memory management ,如果禁用automatic memory management 则这个值为1,如果pga自动管理则这个值是2,如果是automatic memory management 启用,则这个值是4。
另外,我们还可以_cleanup_rollback_entries
,从默认值100改到400,来加快并发回滚的速度,该参数的意义是number of undo entries to apply per transaction clean。
除了上面说的加快,或者减慢(参数往小了调),我们还可以暂时禁用smon的恢复,用10513的事件:
1 2 |
SQL> oradebug setorapid 'SMON's Oracle PID'; SQL> oradebug event 10513 trace name context forever, level 2 |
恢复使用:
1 2 |
SQL> oradebug setorapid 'SMON's Oracle PID'; SQL> oradebug event 10513 trace name context off |
那么在什么情况下我们需要加大并发,什么时候需要串行?
在一般情况下,并发的回滚总是比串行的快,我们一般在系统资源可以接受的范围内采用并发回滚,但是,有一个情况例外,就是并发的子进程之间存在资源冲突的情况。
在并发子进程之间需要的资源冲突时,往往此时smon的等待事件是长期处于Wait for stopper event to be increased
,而子进程的等待事件是较多出现Wait for a undo record
。此时,就是子进程冲突了。并发的回滚速度反而不如串行的回滚速度。
冲突时,我们需要把fast_start_parallel_rollback 改成 false。