使用error stack诊断特定错误信息

 

在实际应用开发中,我们有很多精力倾注在调试程序和异常情况的排查上。使用设计逻辑和场景开发的代码,经常被生产数据一次次的“攻破”。快速的定位错误数据和报错语句是我们提高工作效率的关键。本篇介绍使用Oracleerror stack方法来定位程序包中报错的SQL和取值。

 

1、场景展现

 

我们选择Oracle 11g来进行试验。

 

 

SQL> select * from v$version where rownum<3;

 

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

PL/SQL Release 11.2.0.1.0 – Production

 

 

数据表T包括object_idobject_name列。其中object_id为主键列。

 

 

SQL> create table t (object_id number, object_name varchar2(100));

Table created

 

SQL> alter table t add constraint pk_t primary key (object_id);

Table altered

 

 

灌入一部分基础数据,作为原始值。

 

 

SQL> insert into t select object_id, object_name from dba_objects where wner='SCOTT';

20 rows inserted

 

SQL> commit;

Commit complete

 

 

为了进行实验,我们创建一个procedure程序段,从dba_objects中选取数据插入到数据表T中。程序定义如下:

 

 

SQL> create or replace procedure P_ERRORSTACK_TEST

  2  is

  3  type t_objs_list is table of dba_objects%rowtype index by binary_integer;

  4  t_obj_infos t_objs_list;

  5  begin

  6    select *

  7    bulk collect into t_obj_infos

  8    from dba_objects;

  9 

 10    if (t_obj_infos.count<>0) then

 11       for i in t_obj_infos.first..t_obj_infos.last loop

 12           insert into t

 13           values (t_obj_infos(i).object_id, t_obj_infos(i).object_name);

 14       end loop;

 15    end if;

 16  end P_ERRORSTACK_TEST;

 17  /

 

Procedure created

 

 

注意三个细节:首先,我们是逐条进行数据的插入动作的,而不是insert into select方式。第二,我们在for循环里面插入数据,循环次数多,实际上不能逐条进行检查判断。第三,我们插入的是dba_objects所有的数据,必然一部分插入数据和原始数据表中存在主键冲突的情况。

 

实际执行中,报错。

 

 

SQL> exec P_ERRORSTACK_TEST;

 

begin P_ERRORSTACK_TEST; end;

 

ORA-00001: 违反唯一约束条件 (SCOTT.PK_T)

ORA-06512: "SCOTT.P_ERRORSTACK_TEST", line 12

ORA-06512: line 1

 

 

有过调试和测试经验的朋友们非常熟悉这样的情景。大批量数据测试的时候,存储过程作业包括成千上万相同或者不同的SQL,执行数据海量。执行半天之后,报错。类似的错误还有如长度(数字字符串)超过限制、将空值null插入到非空约束字段,违反外键约束等等。

 

这样的原因无非几种,一是程序的Bug,开发人员没有考虑到业务场景,一般出现在null值计算结果null上。其二是设计问题,业务人员和设计人员没有考虑到当前这样的异常场景。最后也是比较麻烦的,就是测试数据来源有问题,需要进行额外清理工作。

 

无论原因是上述哪种,有两件事情是必须做到,是哪句SQL报错,报错的数据参数值是什么。

 

当然,我们可以认为加入调试代码来输入执行过程,从而实现定位。我们更方便的是使用error stack的诊断事件方法来进行定位。

 

2Error Stack诊断

 

Oracle是一个极其复杂的体系。为了便于进行调试和诊断,Oracle提供了很多的“后门”装置。我们最熟悉的1004610053就是用来诊断SQL语句执行过程和优化器工作情况的。

 

Error Stack是另一种诊断事件。当启动诊断事件时候,需要设置一个错误编号ora。在启动跟踪过程中,一旦报错指定的codeOracle就会将当前信息,如SQL和内存栈情况dumptrace文件。

 

10046一样,error stack也有对应的level取值。目前我们常用的取值有4个等级。一般为了进行诊断,笔者建议将最高等级信息输出比较好。

 

下面我们使用error stack来解决问题。

 

 

--启动error stack监控过程

SQL> alter session set events '1 trace name errorstack level 4';

Session altered

 

SQL> exec P_ERRORSTACK_TEST;

 

begin P_ERRORSTACK_TEST; end;

 

ORA-00001: 违反唯一约束条件 (SCOTT.PK_T)

ORA-06512: "SCOTT.P_ERRORSTACK_TEST", line 12

ORA-06512: line 1

 

--关闭过程

SQL> alter session set events '1 trace name errorstack off';

Session altered

 

 

注意:error stack可以在systemsession level进行设置。我们使用session level就可以满足大部分场景的处理要求了。

 

检查视图v$diag_info,来定位trace文件位置。

 

 

SQL> select value from v$diag_info where name='Default Trace File';

 

VALUE

--------------------------------------------------------------------------------

/u01/diag/rdbms/wilson/wilson/trace/wilson_ora_3813.trc

 

 

此时,我们在指定目录下面可以找到文件。

 

 

[oracle@bspdev ~]$ cd /u01/diag/rdbms/wilson/wilson/trace/

[oracle@bspdev trace]$ ls -l | grep 3813

-rw-r----- 1 oracle oinstall  7866074 Sep  4 05:20 wilson_ora_3813.trc

-rw-r----- 1 oracle oinstall   210205 Sep  4 05:20 wilson_ora_3813.trm

 

 

下面要做的就是解析trace文件。

 

3Trace文件解析

 

应该说,使用最高level生成的诊断文件,体积是很大的。其中一些内部的信息,也是很有学习和参考意义。但是对于诊断来说,数据检索定位是非常重要的。

 

首先,我们在文件头,可以发现错误SQL语句的信息。Oracle显然在报错的时候,将SQL语句捕获到。

 

 

dbkedDefDump(): Starting a non-incident diagnostic dump (flags=0x0, level=4, mask=0x0)

----- Error Stack Dump -----

ORA-00001: 违反唯一约束条件 (SCOTT.PK_T)

----- Current SQL Statement for this session (sql_id=ccf9mag4p402f) -----

INSERT INTO T VALUES (:B1 , :B2 )

----- PL/SQL Stack -----

----- PL/SQL Call Stack -----

  object      line  object

  handle    number  name

0x4b5df860        12  procedure SCOTT.P_ERRORSTACK_TEST

0x497b9ee0         1  anonymous block

 

 

error stack调用结构中,我们可以定位到具体是哪一个方法报错,哪一个SQL报错。Object handle表示PL/SQL程序块在内存中缓存的结构。这里,我们定位到了报错语句SQL,是sql_id= ccf9mag4p402finsert语句。

 

之后,在trace文件中进行检索sql_id信息,找到了语句的执行过程Trace

 

 

----- Dump Cursor sql_id=ccf9mag4p402f xsc=0x559a168 cur=0x700d60 -----

 

LibraryHandle:  Address=4b5d671c Hash=c952004e LockMode=N PinMode=0 LoadLockMode=0 Status=VALD

  ObjectName:  Name=INSERT INTO T VALUES (:B1 , :B2 )

 

    FullHashValue=ecb9f90364e2dbcec6393353c952004e Namespace=SQL AREA(00) Type=CURSOR(00) Identifier=3377594446 wnerIdn=84

  Statistics:  InvalidationCount=0 ExecutionCount=143716 LoadCount=2 ActiveLocks=1 TotalLockCount=1 TotalPinCount=1

  Counters:  BrokenCount=1 RevocablePointer=1 KeepDependency=1 KeepHandle=1 BucketInUse=1 HandleInUse=1

  Concurrency:  DependencyMutex=4b5d6784(0, 3, 0, 0) Mutex=4b5d67d0(43, 22, 0, 6)

 (篇幅原因,有省略……

 kgsccflg=9 llk[0x559a16c,0x559a16c] idx=1004f

 xscflg=c0110676 fl2=1d020000 fl3=422a2188 fl4=100

----- Bind Byte Code (IN) -----

  Opcode = 6   Bind Rpi Scalar Sql In(may be out) Nocopy NoSkip

  Offsi = 36, ffsi = 0

  Opcode = 6   Bind Rpi Scalar Sql In(may be out) Nocopy NoSkip

  Offsi = 36, ffsi = 20

----- Bind Info (kkscoacd) -----

 Bind#0

  oacdty=02 mxl=22(21) mxlc=00 mal=00 scl=00 pre=00

  oacflg=13 fl2=206001 frm=00 csi=00 siz=24 ff=0

  kxsbbbfp=0072e3d4  bln=22  avl=04  flg=09

  value=73180

 Bind#1

  oacdty=01 mxl=128(128) mxlc=00 mal=00 scl=00 pre=00

  oacflg=13 fl2=206001 frm=01 csi=873 siz=128 ff=0

  kxsbbbfp=0072e404  bln=128  avl=07  flg=09

  value="PK_DEPT"

 Frames pfr 0x559a110 siz=2572 efr 0x559a088 siz=2532

 Cursor frame. dump

  enxt: 3.0x000004c4  enxt: 2.0x00000028  enxt: 1.0x000004f8

  pnxt: 1.0x00000028

 kxscphp=0x739424 siz=1000 inu=384 nps=224

 kxscbhp=0x33e3060 siz=1000 inu=92 nps=0

Starting SQL statement dump

SQL Information

user_id=84 user_name=SCOTT module=PL/SQL Developer action=Command Window - New

sql_id=ccf9mag4p402f plan_hash_value=0 problem_type=0

 

 

注意后面标红的部分说明这个SQL有两个绑定变量,重要的是记录了绑定变量当前的取值:object_id73180。表明SQL在插入到73180的时候,报错发生。

 

我们验证一下。

 

 

SQL> select object_id from t;

 

 OBJECT_ID

----------

     73179

     73180

     73181

     73182

 (篇幅原因,有省略……

 

     78028

 

20 rows selected

 

 

当前数据表中已经存在73180,主键重复必然报错。

 

4、结论

 

Error stack是一个非常方便的小工具,可以在诊断、调试程序的时候帮助解决很多问题。

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

转载于:http://blog.itpub.net/17203031/viewspace-772116/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值