监控长时间运行的PL/SQL块

7

我有一个相当耗时的PL/SQL块,用于从分子结构中构建指纹。我想将输出打印到SQL*Plus控制台,以提供有关已处理多少个结构的反馈。我可以使用dbms_output.put_line来实现这一点。

但是每次调用它都会写入一行新内容。我想覆盖该行。

例如,当前我有以下内容。

Structure x of y processed
Structure x of y processed
Structure x of y processed
Structure x of y processed

当我处理成千上万的结构记录时,最终我会填满缓冲区。

有没有一种方法可以只覆盖最后一行输出?

3个回答

16

使用DBMS_OUTPUT意味着 SQL*Plus 会一直等待整个 PL/SQL 块完成,然后显示缓冲区内的所有数据。因此,它不适合用作提供持续状态信息的方式。

另一方面,Oracle 提供了一个包DBMS_APPLICATION_INFO,专门设计用来帮助您监视正在运行的代码。例如,您可以执行以下操作:

CREATE PROCEDURE process_structures
AS
  <<other variable declarations>>

  rindex    BINARY_INTEGER;
  slno      BINARY_INTEGER;
  totalwork NUMBER := y; -- Total number of structures
  worksofar NUMBER := 0; -- Number of structures processed
BEGIN
  rindex := dbms_application_info.set_session_longops_nohint;

  FOR i IN (<<select structures to process>>)
  LOOP
    worksofar := worksofar + 1;
    dbms_application_info.set_session_longops(
        rindex      => rindex, 
        slno        => slno,
        op_name     => 'Processing of Molecular Structures', 
        sofar       => worksofar , 
        totalwork   => totalwork, 
        target_desc => 'Some description',
        units       => 'structures');
    <<process your structure with your existing code>>
  END LOOP;
END;

你可以从单独的 SQL*Plus 会话中,通过查询 V$SESSION_LONGOPS 视图来监控进度。

SELECT opname,
       target_desc,
       sofar,
       totalwork,
       units,
       elapsed_seconds,
       time_remaining
  FROM v$session_longops
 WHERE opname = 'Processing of Molecular Structures';

1

您还可以向命名管道发送消息,并让另一个进程从管道中读取消息。

   procedure sendmessage(p_pipename varchar2
                        ,p_message  varchar2) is
      s number(15);
   begin
      begin
         sys.dbms_pipe.pack_message(p_message);
      exception
         when others then
            sys.dbms_pipe.reset_buffer;
      end;

      s := sys.dbms_pipe.send_message(p_pipename, 0);

      if s = 1
      then
         sys.dbms_pipe.purge(p_pipename);
      end if;
   end; 


   function receivemessage(p_pipename varchar2
                          ,p_timeout  integer) return varchar2 is
      n   number(15);
      chr varchar2(200);
   begin
      n := sys.dbms_pipe.receive_message(p_pipename, p_timeout);

      if n = 1
      then
         return null;
      end if;

      sys.dbms_pipe.unpack_message(chr);
      return(chr);
   end;

0

我认为你做不到。据我所知,dbms_output就是不能这样工作的。

我建议你使用put来回显每1000个条目的单个点和换行符,以便查看是否有进展,并将当前位置写入表格或序列中,以便在需要时进行查看。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接