我使用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的select查询有时需要2-3分钟才能执行,但在日志表中我看到STR_TIME和END_TIME之间的区别只有几秒钟。
如何捕获程序占用的总时间,包括查询执行时间?
答案 0 :(得分:1)
您可以尝试将此过程拆分为两个打包过程,然后应用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;
答案 1 :(得分:1)
一旦你的程序将ref光标移回调用进程,它就无法知道它会发生什么。调用者甚至可能永远不会从游标中获取所有行。调用者可以记录接下来发生的事情。
答案 2 :(得分:0)
你不能从程序内部说出来。 The OPEN FOR
statement:
...将游标变量与查询相关联,分配数据库资源以处理查询,识别结果集,并将光标定位在结果集的第一行之前。
您在程序中的所有时间都是生成查询文本所需的时间以及打开光标所需的时间。然后程序结束,调用者接管OUT引用光标。你无法从这里看到光标发生了什么。
调用者(可能)获取数据,这占用了大部分时间;但也可能正在做其他处理。你需要调用者记录它调用你的程序和它完成后关闭ref光标的时间 - 但是它仍然包括它所做的任何其他处理,所以你不能分开实际上从游标查询处理和提取多少。
如果距离足够近,那么如果您不希望调用者不必担心,那么您可能会有第二个关闭光标并记录时间的过程。你可以打开&#39;打开&#39;光标在会话变量中记录开始时间(使包有状态)并使&#39;关闭&#39;过程检索并插入日志记录;或者打开&#39;使用null结束时间将初始插入到日志记录表中,然后关闭&#39;关闭&#39;用实际结束时间更新该记录。但同样,它只是近似的。
如果确实希望在该过程中完成所有操作,则必须在其中执行所有查询处理,这可能意味着将光标大量收集到集合中并使用该集合类型作为OUT参数,调整你的调用者迭代它而不是光标。当然,这也有更多的内存开销,所以可能不实用。