ITPub博客

首页 > 数据库 > Oracle > 如何能监控rollback的进度

如何能监控rollback的进度

Oracle 作者:hd_system 时间:2016-11-09 15:41:16 0 删除 编辑
如果一个会话正在回滚,如何知道回滚的进度?如何知道还需要多长时间才能回滚结束?下面做一个简单的总结:
[@more@]=========================
一、对于死事务
对死事务,可以查询x$ktuxe: [K]ernel [T]ransaction [U]ndo Transa[x]tion [E]ntry
--for dead transactions 
set serverout on
declare
l_start number;
l_end number;
l_interval number :=60;
begin
dbms_output.enable(10000);
select ktuxesiz into l_start from x$ktuxe where KTUXEUSN=10 and KTUXESLT=39 --代表死事务;
dbms_lock.sleep(l_interval);
select ktuxesiz into l_end from x$ktuxe where KTUXEUSN=10 and KTUXESLT=39;
if nvl(l_start,0)<>nvl(l_end,0) then
if nvl(l_start,0)>nvl(l_end,0) then
dbms_output.put_line('Rolling back ! Time est Second:'|| round(l_end/(l_start -l_end)*l_interval,2));
elsif nvl(l_start,0)<nvl(l_end,0) then="" dbms_output.put_line('performing="" dmls');="" end="" if;="" else="" dbms_output.put_line('session="" is="" waiting="" for="" commit="" or="" rollback!="" can="" not="" estimate="" finish="" time="" ');="" exception="" when="" no_data_found="" dbms_output.put_line('no="" active="" transaction');="" end;="" 我们不能直接得到回滚所需时间,而是通过取两次事务的undo数据块差与耗费的时间做比较,从而推算出回滚的进度。="========================" 二、对于活动事务="" 如果是活动的事务,则有多种方法:="" 1.="" x$ktuxe="" 方法和查询死事务一样,只是把条件ktuxeusn="10" and="" ktuxeslt="39这个条件去掉即可。" 如果是并行rollback,x$ktuxe会有多条记录。目前尚未找到能精确定位到某一个正在的会话在x$ktuxe对应的记录,只是通过一些简单的判断确定具体的记录,然后用和上面类似的方法推算进度。="" 2.="" 通过v$transaction推算="" 这种方法适用于两种情况:="" 1).="" 用户或程序正常发出rollback="" 2).="" 会话处于活动状态(active)时被kill,且状态为active或者killed(ora-00031:="" session="" marked="" kill)="" --for="" transactions="" set="" serverout="" on="" declare="" l_start="" number;="" l_end="" l_interval="" number="" :="30;" l_sid="" begin="" l_sid:="&sid;" select="" a.used_ublk="" into="" from="" v$transaction="" a,="" v$session="" b="" where="" a.addr="b.taddr" sid="L_SID;" dbms_lock.sleep(l_interval);="" if="" nvl(l_start,0)nvl(l_end,0) then
if nvl(l_start,0)>nvl(l_end,0) then
dbms_output.put_line('Rolling back ! Time est Second:'|| round(l_end/(l_start -l_end)*l_interval,2));
elsif nvl(l_start,0)<nvl(l_end,0) then="" dbms_output.put_line('performing="" dmls');="" end="" if;="" else="" dbms_output.put_line('session="" is="" waiting="" for="" commit="" or="" rollback!="" can="" not="" estimate="" finish="" time="" ');="" exception="" when="" no_data_found="" dbms_output.put_line('no="" active="" transaction');="" end;="" 原理和方法和上面提到的都一致,这里不再赘述。这种方法可以精确定位具体的会话。="" 3.="" 直接查询v$session_longops="" 如果满足如下条件:="" .="" 如果数据库版本大于等于10g
. 运行时间超过6秒
. 在会话中发出rollback(命令手工发出或者软件发出)

则进度直接可以通过v$session_longops获得:
--for 10g and above
select * from v$session_longops where sofar<>totalwork and opname='Transaction Rollback';

4: V$FAST_START_TRANSACTIONS
这种方法适用于
1) 实例恢复进度监控
2)对异常中断的事务的回滚的进度(被kill时会话是非活动的,或者被正常kill,没有出现ORA-00031: session marked for kill信息)

这几种情况可以可以查看V$FAST_START_TRANSACTIONS来判断回滚进度。

重要关注这个视图的两个字段:
UNDOBLOCKSDONE:已经回滚了多少undo block
UNDOBLOCKSTOTAL:总共需要回滚多少undo block

如一个有大事务未提交的会话被异常中断,如被kill,我们就可以从后台看到这个被异常中断的会话对应的事务的回滚过程:
SQL> select state,undoblocksdone,undoblockstotal from V$FAST_START_TRANSACTIONS ;

STATE UNDOBLOCKSDONE UNDOBLOCKSTOTAL
---------------- -------------- ---------------
RECOVERING 659 1469

......
SQL> select state,undoblocksdone,undoblockstotal from V$FAST_START_TRANSACTIONS ;

STATE UNDOBLOCKSDONE UNDOBLOCKSTOTAL
---------------- -------------- ---------------
RECOVERED 1469 1469 

可以写一个和上面v$transaction方式类似的过程来推算回滚的结束时间。

declare
l_start number;
l_end number;
l_total number;
l_interval number :=30;
begin
select sum(UNDOBLOCKSDONE) ,sum(UNDOBLOCKSTOTAL) into l_start,l_total from V$FAST_START_TRANSACTIONS where state='RECOVERING';
dbms_lock.sleep(l_interval);
select sum(UNDOBLOCKSDONE) into l_end from V$FAST_START_TRANSACTIONS where state='RECOVERING';
dbms_output.put_line('Rolling back ! Time est Second:'|| round((l_total-l_end)/(l_end -l_start)*l_interval,2)); 
end;
/

这种方法有不完美的地方,就是如果不能精确定位某一个会话的回滚进度;如果数据库不断有新的回滚,则结果可能会不准确。

注意:回滚的进度受很多因素的影响,如数据库、主机的繁忙程度等,所以以上所有方法得到的都是在当时条件下回滚所需时间的估算值,实际所需时间不一定和估算值一样。
****************************************************************************************************************************
--for active transactions
--set serverout on 
declare
  l_start    number;
  l_end      number;
  l_interval number := 30;
  l_sid      number;
begin
  L_SID := &sid;
  SELECT a.used_ublk
    into l_start
    FROM v$transaction a, v$session b
   WHERE a.addr = b.taddr
     and sid = L_SID;
  dbms_lock.sleep(l_interval);
  SELECT a.used_ublk
    into l_end
    FROM v$transaction a, v$session b
   WHERE a.addr = b.taddr
     and sid = L_SID;
  if nvl(l_start, 0) <> nvl(l_end, 0) then
    if nvl(l_start, 0) > nvl(l_end, 0) then
      dbms_output.put_line('Rolling back ! Time est Second:' ||
                           round(l_end / (l_start - l_end) * l_interval, 2));
    elsif nvl(l_start, 0) < nvl(l_end, 0) then
      dbms_output.put_line('Performing DMLs');
    end if;
  else
    dbms_output.put_line('Session is waiting for commit or rollback! Can not estimate finish time ');
  end if;
exception
  when no_data_found then
    dbms_output.put_line('No active transaction');
end;
-----------------------------------------------------------------------------------------------------------------------
select /*+ use_hash(o,s,t,q)*/
 t.object_name, o.session_id, s.sql_id, q.sql_text, s.*
  from gv$locked_object o, dba_objects t, gv$session s, gv$sql q
 where t.object_id = o.object_id
   and o.session_id = s.sid
   and s.sql_id = q.sql_id
   and t.object_name = 'TABLE_CHENXU'

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

请登录后发表评论 登录
全部评论

注册时间:2016-10-12

  • 博文量
    149
  • 访问量
    99040