Oracle死事物回滚
2015-01-22 16:38阅读:
死事务,一般是事务正在跑的时候,被kill掉了,或者数据库shutdown
abort了,那么当数据库再次启动的时候,这些事务就需要做回滚。
可以通过下面的语句查到回滚的事务:
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:
select * from v$rollname where usn=xxx
根据上面的语句,我们可以dump出undo block:
alter system dump undo block '' XID ;
如
alter system dump undo block '_SYSSMU33$' XID 33 56 7463;
然后根据dump出来的trace file,可以判断object
number(objn)或者object id(objd)
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的对象:
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的事件:
SQL> oradebug setorapid 'SMON's Oracle PID';
SQL> oradebug event 10513 trace name context forever, level
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。
查询视图V$FAST_START_TRANSACTIONS中字段UNDOBLOCKSDONE,UNDOBLOCKSTOTAL估算smon恢复进度,这里涉及到参数FAST_START_PARALLEL_ROLLBACK的设置,设置方法可以查看Oracle文档。需要注意的是Oracle在回滚大事务并行回滚参数设置存在bug,这时候你可以查询视图v$fast_start_servers中字段STATE
,如果只有一进城处于RECOVERING,其他进程处于IDLE,则可考虑将FAST_START_PARALLEL_ROLLBACK设置为false,关闭并行恢复。如果所有进程都处于RECOVERING状态,则可以考虑加大恢复进程,将其设置为high。
引用
SQL>set linesize 100
SQL>alter session set NLS_DATE_FORMAT='DD-MON-YYYY
HH24:MI:SS';
SQL>select usn, state, undoblockstotal 'Total', undoblocksdone
'Done', undoblockstotal-undoblocksdone
'ToDo',decode(cputime,0,'unknown',sysdate+(((undoblockstotal-undoblocksdone)
/ (undoblocksdone / cputime)) / 86400))
'Estimated time to complete'
from v$fast_start_transactions;
dump undo segment head,查看跟踪文件
引用
SQL> select segment_id, file_id,block_id from
DBA_ROLLBACK_SEGS;
SEGMENT_ID FILE_ID
BLOCK_ID
---------- ---------- ----------
0
1
9
1
2
9
2
2
25
3
2
41
4
2
57
5
2
73
6
2
89
7
2
105
8
2
121
9
2
137
10
2
153
11 rows selected.
SQL> alter system dump datafile 2 block 121;
System altered.
显示部分跟踪文件,从state为10可以看出该slot有未提交的事务,占用的block数为0x0000035e,转化为10进制为862个,这和v$transaction中used_ublk字段数值吻合。
引用
index state cflags wrap#
uel
scn
dba
parent-xid
nub
stmt_num
------------------------------------------------------------------------------------------------
0x00 9
0x00 0x4058 0xffff 0x0000.01143cae
0x00000000 0x0000.000.00000000 0x00000000
0x00000000
0x01 9
0x00 0x4057 0x0003 0x0000.01143a3b
0x00000000 0x0000.000.00000000 0x00000000
0x00000000
0x02 10
0x80 0x4058 0x0008 0x0000.01143fa5
0x00800c8c 0x0000.000.00000000 0x0000035e
0x0000000
观察Oracle内部表x$ktuxe [k]ernel layer
[t]ransaction layer [u]ndo transaction [e]ntry
引用
SQL> desc x$ktuxe
Name
Null?
Type
----------------------------------------- --------
----------------------------
ADDR
RAW(4)
INDX
NUMBER
INST_ID
NUMBER
KTUXEUSN
NUMBER
KTUXESLT
NUMBER
KTUXESQN
NUMBER
KTUXERDBF
NUMBER
KTUXERDBB
NUMBER
KTUXESCNB
NUMBER
KTUXESCNW
NUMBER
KTUXESTA
VARCHAR2(16)
KTUXECFL
VARCHAR2(24)
KTUXEUEL
NUMBER
KTUXEDDBF
NUMBER
KTUXEDDBB
NUMBER
KTUXEPUSN
NUMBER
KTUXEPSLT
NUMBER
KTUXEPSQN
NUMBER
KTUXESIZ
NUMBER
SQL> select distinct ktuxesiz from x$ktuxe where
KTUXESTA='ACTIVE';
KTUXESIZ
----------
862
进一步利用该内部表可以查看死事务的恢复进度
引用
select * from x$ktuxe where ktuxecfl = 'DEAD' and ktuxesta =
'ACTIVE';
初步估算事务恢复进度,注意KTUXEUSN,KTUXESLT为变量
SQL> l
1 select usn, state,
undoblockstotal 'Total', undoblocksdone 'Done',
undoblockstotal-undoblocksdone 'ToDo',
2
decode(cputime,0,'unknown',sysdate+(((undoblockstotal-undoblocksdone)
/ (undoblocksdone / cputime)) / 86400)) 'Estimated time to
complete'
3* from v$fast_start_transactions
SQL> /
USN STATE
Total Done
ToDo Estimated time to compl
---------- ---------------- ---------- ---------- ----------
-----------------------
5 RECOVERING
1263593 718792
544801 23-JAN-2015 01:33:01