昨天一个朋友问我如何监测一个PL/SQL的运行状况,这里简单介绍几种方法。


介绍专业一点的DBMS_APPLICATION_INFO包。


上一篇介绍了通过INSERT和自治事务的解决方案,方法很简单,但是需要辅助的表和过程,而且这种方法显得有点不够专业。


那么这里介绍一篇相对PROFESSIONAL的解决方案,Oracle提供的DBMS_APPLICATION_INFO包:


SQL> SELECT SID, ACTION


 2  FROM V$SESSION


 3  WHERE SID IN


 4  (SELECT SID  


 5  FROM V$MYSTAT


 6  WHERE ROWNUM = 1);


      SID ACTION


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


       13


SQL> BEGIN


 2  DBMS_APPLICATION_INFO.SET_ACTION('STEP A');


 3  DBMS_LOCK.SLEEP(10);


 4  DBMS_APPLICATION_INFO.SET_ACTION('STEP B');


 5  DBMS_LOCK.SLEEP(10);


 6  DBMS_APPLICATION_INFO.SET_ACTION('STEP C');


 7  END;


 8  /


PL/SQL过程已成功完成。


通过简单的调用SET_ACTION过程,其他会话就可以通过监测V$SESSION视图,而从得到当前的PL/SQL执行到哪个步骤:


SQL> SELECT SID, ACTION FROM V$SESSION WHERE SID = 13;


      SID ACTION


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


       13 STEP A


SQL> SELECT SID, ACTION FROM V$SESSION WHERE SID = 13;


      SID ACTION


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


       13 STEP A


SQL> SELECT SID, ACTION FROM V$SESSION WHERE SID = 13;


      SID ACTION


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


       13 STEP B


SQL> SELECT SID, ACTION FROM V$SESSION WHERE SID = 13;


      SID ACTION


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


       13 STEP B


SQL> SELECT SID, ACTION FROM V$SESSION WHERE SID = 13;


      SID ACTION


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


       13 STEP C


SQL> SELECT SID, ACTION FROM V$SESSION WHERE SID = 13;


      SID ACTION


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


       13 STEP C


在另外的会话可以看到,刚才会话的PL/SQL从STEP A到STEP C的变化。需要注意,如果会话不再修改ACTION,那么这个会话的ACTION会一直保持到会话的结束。


这种方法的简单程度一点都不必INSERT的方法复杂,而且DBMS_APPLICATION_INFO包是所有用户都可以访问的。但是需要注意,并不是所有用户都可以访问V$SESSION视图的,这个视图需要额外的授权。


上面的方法似乎还不是很专业,利用这个包还有更专业的解决方案:


SQL> SELECT SID, SERIAL#


 2  FROM V$SESSION


 3  WHERE SID IN


 4  (SELECT SID


 5  FROM V$MYSTAT


 6  WHERE ROWNUM = 1);


      SID    SERIAL#


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


       13       6610


SQL> DECLARE


 2     V_ID BINARY_INTEGER := DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS_NOHINT;


 3     V_SLNO BINARY_INTEGER;


 4     V_TOTALWORK NUMBER := 5;


 5  BEGIN


 6     FOR I IN 1..V_TOTALWORK LOOP


 7             DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS(


 8                     V_ID,


 9                     V_SLNO,


10                     'ANONYMOUS BLOCK',


11                     0,


12                     0,


13                     I - 1,


14                     V_TOTALWORK,


15                     'PL/SQL',


16                     'STEP');


17             DBMS_LOCK.SLEEP(10);


18     END LOOP;


19     DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS(


20             V_ID,


21             V_SLNO,


22             'ANONYMOUS BLOCK',


23             0,


24             0,


25             V_TOTALWORK,


26             V_TOTALWORK,


27             'PL/SQL',


28             'STEP');


29  END;


30  /


PL/SQL过程已成功完成。


通过SET_SESSSION_LONGOPS过程,可以使得PL/SQL代码更新V$SESSION_LONGOPS视图的结果,其他用户不仅可以看到当前在执行什么操作,而且还可以根据用户设置的SOFAR和TOTALWORK的值,了解当前运行到PL/SQL中的什么位置。V$SESSION_LONGOPS会根据运行的时间,以及SOFAR和TOTALWORK的值,自动估算运行还需要多久才能完成:


SQL> SELECT OPNAME, TARGET, TARGET_DESC, SOFAR, TOTALWORK, UNITS, TIME_REMAINING, ELAPSED_SECONDS


 2  FROM V$SESSION_LONGOPS


 3  WHERE SID = 13


 4  AND SERIAL# = 6610;


OPNAME          TARGET TARGET_DESC    SOFAR  TOTALWORK UNITS TIME_REMAINING ELAPSED_SECONDS


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


ANONYMOUS BLOCK        PL/SQL             0          5 STEP                               0


SQL> SELECT OPNAME, TARGET, TARGET_DESC, SOFAR, TOTALWORK, UNITS, TIME_REMAINING, ELAPSED_SECONDS


 2  FROM V$SESSION_LONGOPS


 3  WHERE SID = 13


 4  AND SERIAL# = 6610;


OPNAME          TARGET TARGET_DESC    SOFAR  TOTALWORK UNITS TIME_REMAINING ELAPSED_SECONDS


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


ANONYMOUS BLOCK        PL/SQL             1          5 STEP              32               8


SQL> SELECT OPNAME, TARGET, TARGET_DESC, SOFAR, TOTALWORK, UNITS, TIME_REMAINING, ELAPSED_SECONDS


 2  FROM V$SESSION_LONGOPS


 3  WHERE SID = 13


 4  AND SERIAL# = 6610;


OPNAME          TARGET TARGET_DESC    SOFAR  TOTALWORK UNITS TIME_REMAINING ELAPSED_SECONDS


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


ANONYMOUS BLOCK        PL/SQL             1          5 STEP              32               8


SQL> SELECT OPNAME, TARGET, TARGET_DESC, SOFAR, TOTALWORK, UNITS, TIME_REMAINING, ELAPSED_SECONDS


 2  FROM V$SESSION_LONGOPS


 3  WHERE SID = 13


 4  AND SERIAL# = 6610;


OPNAME          TARGET TARGET_DESC    SOFAR  TOTALWORK UNITS TIME_REMAINING ELAPSED_SECONDS


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


ANONYMOUS BLOCK        PL/SQL             2          5 STEP              30              20


SQL> SELECT OPNAME, TARGET, TARGET_DESC, SOFAR, TOTALWORK, UNITS, TIME_REMAINING, ELAPSED_SECONDS


 2  FROM V$SESSION_LONGOPS


 3  WHERE SID = 13


 4  AND SERIAL# = 6610;


OPNAME          TARGET TARGET_DESC    SOFAR  TOTALWORK UNITS TIME_REMAINING ELAPSED_SECONDS


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


ANONYMOUS BLOCK        PL/SQL             3          5 STEP              19              29


SQL> SELECT OPNAME, TARGET, TARGET_DESC, SOFAR, TOTALWORK, UNITS, TIME_REMAINING, ELAPSED_SECONDS


 2  FROM V$SESSION_LONGOPS


 3  WHERE SID = 13


 4  AND SERIAL# = 6610;


OPNAME          TARGET TARGET_DESC    SOFAR  TOTALWORK UNITS TIME_REMAINING ELAPSED_SECONDS


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


ANONYMOUS BLOCK        PL/SQL             4          5 STEP              10              38


SQL> SELECT OPNAME, TARGET, TARGET_DESC, SOFAR, TOTALWORK, UNITS, TIME_REMAINING, ELAPSED_SECONDS


 2  FROM V$SESSION_LONGOPS


 3  WHERE SID = 13


 4  AND SERIAL# = 6610;


OPNAME          TARGET TARGET_DESC    SOFAR  TOTALWORK UNITS TIME_REMAINING ELAPSED_SECONDS


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


ANONYMOUS BLOCK        PL/SQL             4          5 STEP              10              38


SQL> SELECT OPNAME, TARGET, TARGET_DESC, SOFAR, TOTALWORK, UNITS, TIME_REMAINING, ELAPSED_SECONDS


 2  FROM V$SESSION_LONGOPS


 3  WHERE SID = 13


 4  AND SERIAL# = 6610;


OPNAME          TARGET TARGET_DESC    SOFAR  TOTALWORK UNITS TIME_REMAINING ELAPSED_SECONDS


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


ANONYMOUS BLOCK        PL/SQL             5          5 STEP               0              50


同样,V$SESSION_LONGOPS不是所有会话都可以直接访问的,需要授权的用户才可以访问,这种方法的最大好处是,用户可以自己量化运行的阶段,使得其他用户监测V$SESSION_LONGOPS视图的时候可以得到估算的运行结束时间。不过时间是否准确与用户设置的值有关。


oracle视频教程请关注:http://u.youku.com/user_video/id_UMzAzMjkxMjE2.html