【问题标题】:How to find Ref Cursor execution time in procedure?如何在程序中找到 Ref Cursor 执行时间?
【发布时间】:2018-03-27 07:31:51
【问题描述】:

我使用 Ref Cursor 作为 PLSQL 过程的输出参数。我需要在日志表中维护 proc 的确切开始和结束时间。

下面的虚拟代码:

Procedure(P1 IN NUMBER, P_REF_CUR OUT SYS_REFCURSOR)
IS
V_TS TIMESTAMP;
BEGIN
V_TS := SYSTIMESTAMP;
<Business logic here to generate SELECT query for Ref Cursor...>;

OPEN P_REF_CUR FOR <SELECT QUERY>;

INSERT INTO LOG_TABLE(ID, STR_TIME,END_TIME,..) VALUES 
(1,V_TS,SYSTIMESTAMP,...);
END;

Ref Cursor 的选择查询有时需要 2-3 分钟才能执行,但在日志表中,我看到 STR_TIME 和 END_TIME 之间的差异只有几秒钟。

如何捕获过程所花费的总时间,包括查询执行时间?

【问题讨论】:

  • 总“查询执行时间”到底是什么意思? 2-3 分钟大概包括获取和显示所有数据,根据使用的工具,可能会有额外的网络延迟。我假设您想要打开-获取-关闭和处理整个结果集的相应总时间?。
  • 报告工具调用此过程生成报告。此报告生成需要一些时间,主要是查询执行时间,这是我想要查找并登录我的日志表的时间。如果我 EXECUTE "SELECT COUNT(*) INTO VAR FROM (CURSOR SELECT QUERY)" ,它会给我查询执行时间吗?

标签: oracle plsql ref-cursor


【解决方案1】:

一旦您的过程将 ref 光标返回给调用进程,它就无法知道会发生什么。调用者甚至可能永远不会从游标中获取所有行。由调用者记录接下来发生的事情。

【讨论】:

    【解决方案2】:

    您可以尝试将此程序拆分为两个打包程序,并申请set timing on

    SQL> create or replace package myPkg is
            procedure pr1(P1 IN NUMBER);
            procedure pr2(P_REF_CUR OUT SYS_REFCURSOR);
    end;
    /
    
    SQL> create or replace package body myPkg is
        v_ts  timestamp;
      procedure pr1(P1 IN NUMBER) is
      begin
        v_ts := SYSTIMESTAMP;
        <Business logic here to generate SELECT query for Ref Cursor...>;  
      end;
    
      procedure pr2(P_REF_CUR OUT SYS_REFCURSOR) is
      begin
        open P_REF_CUR for <SELECT QUERY>;
        insert into log_table(ID, STR_TIME,END_TIME,..) values(1,V_TS,SYSTIMESTAMP,...);  
      end;  
    end;
    /
    
    SQL> set timing on;
    SQL> var v_p1 number:=107;
    SQL> var v_rc refcursor;
    SQL> exec myPkg.pr1( :v_p1 );
    
    PL/SQL procedure successfully completed
    
    Executed in 152,25 seconds
    
    SQL> exec myPkg.pr2( :v_rc );
    
    PL/SQL procedure successfully completed
    
    Executed in 12,34 seconds
    
    SQL> print v_rc;
    

    【讨论】:

    • 这仍然只会告诉您open 花了多长时间,而不是获取所有数据需要多长时间?此外,您的 V_TS 需要一个数据类型,并且只会在包实例化时设置,因此您需要在每次调用这对过程时重置它 - 大概在 pr1 内部?
    • @AlexPoole 非常感谢 Alex,我已经按照您对 v_ts 的警告进行了编辑。
    【解决方案3】:

    您无法从程序内部分辨出来。 The OPEN FOR statement:

    ... 将游标变量与查询相关联,分配数据库资源来处理查询,标识结果集,并将游标定位在结果集的第一行之前。

    在您的过程中,您所能做的就是生成查询文本所需的时间以及打开光标所需的时间。然后该过程结束,调用者接管 OUT 引用游标。从这里你看不到光标发生了什么。

    调用者比(大概)获取数据,这占用了大部分时间;但也可能在做其他处理。您需要调用者记录它调用您的过程之间的时间,以及它在完成它时关闭参考游标的时间 - 但这仍将包括它所做的任何额外处理,因此您无法从实际中分离出多少游标查询处理和获取。

    如果这足够接近,那么如果您不想让调用者担心它,那么您可能有第二个过程来关闭游标并记录时间。您可以让“打开”游标在会话变量中记录开始时间(使包有状态),并让“关闭”过程检索它并插入日志记录;或者让“打开”以空结束时间对记录表进行初始插入,然后让“关闭”用实际结束时间更新该记录。但同样,这只是近似值。

    如果您真的想在该过程中完成所有操作,那么您必须在其中进行所有查询处理,这可能意味着将光标批量收集到一个集合中并将该集合类型用作OUT 参数,调整调用者以迭代它而不是光标。当然,这也有更多的内存开销,所以可能不实用。

    【讨论】:

      猜你喜欢
      • 2011-10-24
      • 1970-01-01
      • 2012-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多