编译存储过程遇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。