编译存储过程遇ddl锁

有时候我们对存储过程的一个新的版本需要上线,可能是做了性能优化或者是功能的添加或改进,如果此时存储过程正在被程序调用,执行起来会花很长时间,这可能已经超出了我们的上线窗口,那怎么办,有些人可能会想到将客户端的连接断开,支持会话的服务器进程自然会被pmon所清理,但是往往事与愿违,存储过程依旧在执行,最有效的办法是在服务器上找到对应将此会话所session 所对应的会话杀了,还不行只有物理上干掉服务器进程了.
首先要做的是找到server process 的sid;
执行存储过程的时候需要获取对象上的ddl 琐,对于执行会话是以共享模式获取,而对与要编译存储过程的会话,则是要以排它模式获取,
如何查看持有ddl索的会话id那?oracle 为我们提供了一个很有用的视图:dba_ddl_locks.

下面模拟测试,首先执行存储过程 PROC_TEST,

首先执行存储过程 PROC_TEST,

session s1:

begin
  -- Call the procedure
  proc_test;
end;/

session s2中去编译它

session s2:

1 create or replace procedure proc_test is
2 n_num number :=0;
3 n_cnt number;
4 start_time number;
5 end_time number;
6 begi
7 ..........省略。

此时已显示等待(何时结束,未知)
数据库中会话的状态

select sid,command,blocking_Session,event from v$session where status='ACTIVE' and module='PL/SQL Developer'
    SID COMMAND BLOCKING_SESSION EVENT
1 45 3   db file scattered read
2 434 24 45 library cache pin

显然sid为45的会话挡住了sid为434 即我要编译代码的会话

检查dba_ddl_locks视图更清晰的看到

    SESSION_ID OWNER NAME TYPE MODE_HELD MODE_REQUESTED
1 45 MHISKFDATA PROC_TEST Table/Procedure/Type Null None
2 434 MHISKFDATA PROC_TEST Table/Procedure/Type Exclusive None

 v$lock 显示如下

 select * from v$lock where sid in ('45','434') order by  sid;

ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK
00002B0774D9C4D8 00002B0774D9C538 45 TM 96902 0 3 0 2754 0
00000000FA47BE08 00000000FA47BE60 45 AE 100 0 4 0 2757 0
00000000F6FC7258 00000000F6FC72D0 45 TX 720925 365753 6 0 2753 0
00000000FA47D320 00000000FA47D378 434 AE 100 0 4 0 2085 0
00000000FA479120 00000000FA479178 434 AE 0 1 4 0 226 0

此时要做的是杀掉45的会话即可

select 'alter system kill session '''||sid||','||serial#||''' immediate;' from v$session  where sid='45';

1 alter system kill session '45,39175' immediate;

再次编译应该没问题了。

如果还有问题那么就只好杀进程了

select p.spid from v$process p, v$session s where p.addr = s.paddr and s.sid='45';

linux 下

kill  -9 &spid。

原文地址:https://www.cnblogs.com/wangxingc/p/5184145.html