昨天一个朋友问我如何监测一个PL/SQL的运行状况,这里简单介绍几种方法。
介绍更专业的DBMS_PIPE实现方式。
如果觉得DBMS_APPLICATION_INFO包还不够专业,这里再介绍一篇更加PROFESSIONAL的解决方案,通过DBMS_PIPE实现进程间通信。
利用这种方法,进行操作的PL/SQL过程可以通过管道发送消息给接收进程。下面给出一个最简单的例子:
SQL> CREATE TABLE T_RECORD
2 (STR VARCHAR2(30),
3 TIME DATE);
表已创建。
建立一个记录表。
随后,负责监测的进程启动一个PIPE,然后定时检测PIPE中是否存在数据:
SQL> DECLARE
2 V_RETURN NUMBER;
3 V_STR VARCHAR2(32767);
4 BEGIN
5 V_RETURN := DBMS_PIPE.CREATE_PIPE('P_TEST');
6 WHILE (V_RETURN = 0) LOOP
7 V_RETURN := DBMS_PIPE.RECEIVE_MESSAGE('P_TEST', 360);
8 IF V_RETURN = 0 THEN
9 DBMS_PIPE.UNPACK_MESSAGE(V_STR);
10 INSERT INTO T_RECORD VALUES (V_STR, SYSDATE);
11 END IF;
12 END LOOP;
13 V_RETURN := DBMS_PIPE.REMOVE_PIPE('P_TEST');
14 END;
15 /
需要注意,正常情况下,很可能这个PL/SQL一直处于监测状态,不过这就需要修改过程使得过程中提交事务。
当前例子为了简单,设置了10分钟的过期时间,确保要监控的PL/SQL发消息的时间间隔小于10分钟。在这10分钟内,在另外的会话运行PL/SQL代码:
SQL> DECLARE
2 V_STR VARCHAR2(4000) := 'STEP BEGIN';
3 V_RETURN NUMBER;
4 BEGIN
5 DBMS_PIPE.PACK_MESSAGE(V_STR);
6 V_RETURN := DBMS_PIPE.SEND_MESSAGE('P_TEST');
7 DBMS_LOCK.SLEEP(60);
8 V_STR := 'STEP MIDDLE';
9 DBMS_PIPE.PACK_MESSAGE(V_STR);
10 V_RETURN := DBMS_PIPE.SEND_MESSAGE('P_TEST');
11 DBMS_LOCK.SLEEP(60);
12 V_STR := 'STEP END';
13 DBMS_PIPE.PACK_MESSAGE(V_STR);
14 V_RETURN := DBMS_PIPE.SEND_MESSAGE('P_TEST');
15 END;
16 /
PL/SQL过程已成功完成。
当这个代码运行结束10分钟后,前面监测过程由于超时退出运行,这时检查日志信息:
PL/SQL过程已成功完成。
SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
会话已更改。
SQL> SELECT * FROM T_RECORD;
STR TIME
------------------------------ -------------------
STEP BEGIN 2010-04-28 16:33:43
STEP MIDDLE 2010-04-28 16:34:43
STEP END 2010-04-28 16:35:43
这种方法适用于专门的监测程序。不过DBMS_PIPE包需要额外的授权