oracle查询过程中卡住,查看Oracle中存储过程长时间被卡住的
原因
1:查V$DB_OBJECT_CACHE
SELECT * FROM V$DB_OBJECT_CACHE WHERE name=‘CUX_OE_ORDER_RPT_PKG‘ AND LOCKS!=‘0‘;
注意:CUX_OE_ORDER_RPT_PKG 为存储过程的名称。
发现locks=2
2:按对象查出sid的值
select /*+ rule*/  SID from V$ACCESS WHERE object=‘CUX_OE_ORDER_RPT_PKG‘;
注意:CUX_OE_ORDER_RPT_PKG 为存储过程的名称。
3:查sid,serial#
SELECT SID,SERIAL#,PADDR FROM V$SESSION WHERE SID=‘刚才查到的SID‘;
4、根据会话id(sid),此会话的等待事件:
select * from v$session where sid=***;
event字段即为等待事件。查询后我们发现这个会话等待事件为SQL*Net message from dblink;在查看会话的logon_time为两天前。这个时间远超过我们估计时间。
5、根据会话id查看此会话正在执⾏的sql语句
select sql_text from v$sqlarea where address= (select  sql_address  from v$session where sid=***);
查询后发现正在执⾏的sql语句为通过dblink到远程数据库上A表查询数据,插⼊到B表。
6、连接远程数据库,查询当前被锁的对象
select * from v$locked_object lo ,
all_objects  ao    where lo.OBJECT_ID= ao.object_id ;
查看后发现远程数据库中并没有涉及到A、B表被锁
7、查看远程数据的会话:
select * from v$session where terminal like ‘%机器名%‘  and program=‘‘
使⽤dblink连接远程数据库,在远程数据库上的会话的program应该是是
查询后发现,两个远程库有时候根本没有相关会话,有时候可能有相关会话,但其等待事件是 SQL*Net message from client 远程库在等待本地Oracle给他发请求。
本地库等dblink远程库,远程库等待client消息。看来这个存储过程是不可能执⾏完了。
具体什么原因造成了,还不清楚。
这⾥给出的处理⽅法就是杀死会话
具体步骤可参考上⾯的⽂章
⼀些项⽬中使⽤了job定期执⾏sql语句。如果要执⾏的sql语句是基于dblink对远程数据库的访问,那么有时候就会出现该sql语句长时间执⾏⼀直不结束的情况。并且这时在远程数据库上并没有锁导致该sql语句等待(这可能是由于⽹络问题触发的oracle的⼀个bug吧,远程数据库与本地数据之间有防⽕墙时⽐较容易出现这个现象)。
下⾯总结了如何判断该job是否长时间执⾏没结束,并说明了处理步骤。
1)、观察job情况。
system⽤户下执⾏语句select * from  dba_jobs;到有问题的job,记录下该job在查询结果中job列的取值,该取值称为job号。
broken字段为N,且this_date字段的时间⽐当前时间减去执⾏周期要晚(根据interval字段判断),则job是正常的。如果this_date字段没有值,⼀般认为job当前没有在执⾏。
如果broken字段N,并且this_date时间不对(例如是⼏个⼩时以前,甚⾄⼏天以前),则说明该job某⼀次周期⼀直没有执⾏完。
如果出现这种现象,就说明该job可能出问题了。
2)、查该job⽬前正在执⾏时的会话编号sid
select * from  dba_jobs_running where job=‘刚才查到的job号‘;
在返回结果中记录sid列的取值
oracle登录命令
3)、查看该会话
select * from v$session where sid=‘刚才查到的sid‘
记录下返回结果的 serial#列(会话序列号),paddr列(线程地址)
4)、 取得会话的线程号
select spid from  v$process  where  addr=‘刚才查到的线程地址‘ ;
记录下列spid,称为线程号
5)、使⽤oracle命令杀会话
alter system kill session ‘会话编号sid,会话序列号serial#‘;
6)、查看是否成功杀掉该会话(⽅法与步骤⼀相同,多执⾏⼏次select * from  dba_jobs;观察结果)
7)、如果没有杀掉会话,就是⽤操作系统命令杀线程(或进程)
这⾥给出windows下杀oracle会话占⽤的线程的⽅法
登录到数据库所在的操作系统中,打开windows命令⾏,键⼊命令:  orakill 数据库sid  刚才查到的线程号spid
例如 orakill orcl  12345
这⾥给出⼀个⾃动清理问题job的存储过程,由于是存储过程,只能使⽤alter system kill 来杀会话,有时候会话只被标记为killed,并不能真正结束,job也⽆法启动下⼀个周期。
CREATE OR REPLACE PROCEDURE SYS.PRO_KILL_JOB AS
/*清理job567 568 569 长期执⾏不结束的情况*/
/*30分钟超时*/
CURSOR  MYCUR    IS
select    ‘ ALTER SYSTEM KILL SESSION ‘‘‘||s.sid ||‘,‘||  s.SERIAL#||‘‘‘ immediate ‘  AS SQL_KILL  , J.JOB
from dba_jobs_running j,v$session s
where  j.sid=s.sid and
this_date
s.sid is not null and s.serial# is not null
and
( j.job= 567
or j.job=568
or j.job=569  ) ;
V_SQL_KILL  VARCHAR2(500);
V_JOB NUMBER ;
BEGIN
OPEN MYCUR;
LOOP
FETCH MYCUR
INTO V_SQL_KILL , V_JOB;
EXIT WHEN MYCUR%NOTFOUND;
dbms_output.put_line(v_sql_kill);
execute immediate  v_sql_kill ;
COMMUNICATION.SP_DB_LOG(‘PRO_KILL_JOB‘, 1, NULL, V_JOB||‘ IS KILLED‘); COMMIT;
END LOOP;
CLOSE MYCUR;
EXCEPTION
WHEN OTHERS THEN
COMMUNICATION.SP_DB_LOG(‘PRO_KILL_JOB‘, 1, SQLCODE, SQLERRM); COMMIT;
END PRO_KILL_JOB;

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。