ITPub博客

首页 > 数据库 > Oracle > 【Oracle】查看事务回滚的时间

【Oracle】查看事务回滚的时间

原创 Oracle 作者:azzotest 时间:2015-09-07 19:46:40 0 删除 编辑
首先,我是做BI的,在工作中偶尔会出现一些特殊情况,比如突然在某天ETL日增量调度的时候一个简单的插入操作卡住不动几小时都过不去,平时可能30分钟左右。
可能是资源征用导致DataStage资源分配不均等各种原因,这个时候通常会有运维的同事协助中断此作业的运行,进行重新插入。

中断后就要开始漫长的等待,等全部rollback后进行rerun这个JOB。

而这时候业务用户就不爽了,为什么都9点了我还看不了报表数据? 通常情况我们会先各种赔礼道歉然后给一个大概的时间点安抚用户,
等待时间基本就是回滚时间 + 重新插数时间,插数时间可以从调度日志中获取历史平均值,而回滚时间就难以获取,这里给大家普及一个查看事物回滚时间的知识点

这里我们不详细讲解DB异常关闭的SMON事务回滚,大概说下:
基本分3种方式:
1. 查询视图V$FAST_START_TRANSACTIONS中字段UNDOBLOCKSDONE,UNDOBLOCKSTOTAL估算smon恢复进度
2. 跟踪日志
3. 查询内部试图x$ktuxe [k]ernel layer [t]ransaction layer [u]ndo transaction [e]ntry 
可参考http://www.ssc.stn.sh.cn/html/zsk/ITyw/2012-04/5819.html

这里主要说下一个insert、delete、update等语句的rollback时间估算
建个测试表

点击(此处)折叠或打开

  1. create table table_chenxu as select * from dba_objects
插入大量数据

点击(此处)折叠或打开

  1. begin
  2. for i in 1..100
  3. loop
  4. insert into table_chenxu
  5. select * from dba_objects;
  6. commit;
  7. end loop;
  8. end;

首先第一步我们要拿到正在回滚的SQL的SQLID和SESSIONID,这个简单,假如我们对table_chenxu进行delete,回滚过程中这个table_chenxu必定是被锁的,所以我们可以根据gv$locked_object来查看当前对象是否被锁,且根据sid查看锁表的SQL

我们先update下这个表
update table_chenxu t set t.owner = 'azzo';

然后查询被锁的相关信息:

注:多个系统视图关联查询的时候为了防止试图合并可以加上use_hash或者no_merge

点击(此处)折叠或打开

  1. select /*+ use_hash(o,s,t,q)*/
  2.  t.object_name, o.session_id, s.sql_id, q.sql_text, s.*
  3.   from gv$locked_object o, dba_objects t, gv$session s, gv$sql q
  4.  where t.object_id = o.object_id
  5.    and o.session_id = s.sid
  6.    and s.sql_id = q.sql_id
  7.    and t.object_name = 'TABLE_CHENXU'
结果如下:



我是PC机,update用了628秒,现在rollback(plsql developer死了。。于是重新开一个):

使用如下SQL查看ktuxesiz字段,过一段时间(如10s)再执行一次,再看一下,两个结果相减除以10就是每秒回滚的速度

点击(此处)折叠或打开

  1. select
  2.       s.username,
  3.       t.xidusn,
  4.       t.xidslot,
  5.       t.xidsqn,
  6.       x.ktuxesiz
  7.     from
  8.       sys.x$ktuxe x,
  9.       sys.v_$transaction t,
  10.       sys.v_$session s
  11.     where
  12.       x.inst_id = userenv('Instance') and
  13.       x.ktuxesta = 'ACTIVE' and
  14.       x.ktuxesiz > 1 and
  15.       t.xidusn = x.ktuxeusn and
  16.       t.xidslot = x.ktuxeslt and
  17.       t.xidsqn = x.ktuxesqn and
  18.       s.saddr = t.ses_addr;

或者使用自动化脚本(取自网络)

点击(此处)折叠或打开

  1. declare
  2.   cursor tx is
  3.     select
  4.       s.username,
  5.       t.xidusn,
  6.       t.xidslot,
  7.       t.xidsqn,
  8.       x.ktuxesiz
  9.     from
  10.       sys.x$ktuxe x,
  11.       sys.v_$transaction t,
  12.       sys.v_$session s
  13.     where
  14.       x.inst_id = userenv('Instance') and
  15.       x.ktuxesta = 'ACTIVE' and
  16.       x.ktuxesiz > 1 and
  17.       t.xidusn = x.ktuxeusn and
  18.       t.xidslot = x.ktuxeslt and
  19.       t.xidsqn = x.ktuxesqn and
  20.       s.saddr = t.ses_addr;
  21.   user_name varchar2(30);
  22.   xid_usn number;
  23.   xid_slot number;
  24.   xid_sqn number;
  25.   used_ublk1 number;
  26.   used_ublk2 number;
  27. begin
  28.   open tx;
  29.   loop
  30.     fetch tx into user_name, xid_usn, xid_slot, xid_sqn, used_ublk1;
  31.     exit when tx%notfound;
  32.     if tx%rowcount = 1
  33.     then
  34.       sys.dbms_lock.sleep(10);
  35.     end if;
  36.     select
  37.       sum(ktuxesiz)
  38.     into
  39.       used_ublk2
  40.     from
  41.       sys.x$ktuxe
  42.     where
  43.       inst_id = userenv('Instance') and
  44.       ktuxeusn = xid_usn and
  45.       ktuxeslt = xid_slot and
  46.       ktuxesqn = xid_sqn and
  47.       ktuxesta = 'ACTIVE';
  48.     if used_ublk2 < used_ublk1
  49.     then
  50.       sys.dbms_output.put_line(
  51.         user_name ||
  52.         '''s transaction ' ||
  53.         xid_usn || '.' ||
  54.         xid_slot || '.' ||
  55.         xid_sqn ||
  56.         ' will finish rolling back at approximately ' ||
  57.         to_char(
  58.           sysdate + used_ublk2 / (used_ublk1 - used_ublk2) / 6 / 60 / 24,
  59.           'HH24:MI:SS DD-MON-YYYY'
  60.         )
  61.       );
  62.     end if;
  63.   end loop;
  64.   if user_name is null
  65.   then
  66.     sys.dbms_output.put_line('No transactions appear to be rolling back.');
  67.   end if;
  68. end;


结果如下:
SCOTT's transaction 8.19.1171 will finish rolling back at approximately 19:47:57 07-9月 -2015


是不是很方便~  不过自动化脚本需要有dba权限哦,sys.dbms_lock.sleep(10)这个包,普通用户是没权限以调用的,如果没有dba权限就掐表及时吧

直到写完这篇文章,我的plsql还在未响应中。。。




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

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

注册时间:2015-08-21

  • 博文量
    22
  • 访问量
    56238