Performance pl/sql存储过程。。。执行时间到哪里去了?

Performance pl/sql存储过程。。。执行时间到哪里去了?,performance,oracle,stored-procedures,plsql,Performance,Oracle,Stored Procedures,Plsql,我目前正在跟踪存储过程中的性能泄漏。 在最初的“开始”之后加上一个时间戳,在最后一个“结束”之前加上一个时间戳(我之前做过一次提交),这说明这个过程大约需要10秒才能完成。 然而,我必须等待2分钟以上,它才能结束 有人能告诉我剩下的时间都到哪里去了吗?我使用的是Oracle SQL dev,但它似乎不会在其余时间处于空闲状态,该过程似乎锁定了相应的表:( 提前非常感谢您的启发 编辑:再次感谢您的输入:) 这是程序的精简代码,取决于要处理的项目数量,第一部分目前大约需要10到40秒,第二部分需要几

我目前正在跟踪存储过程中的性能泄漏。 在最初的“开始”之后加上一个时间戳,在最后一个“结束”之前加上一个时间戳(我之前做过一次提交),这说明这个过程大约需要10秒才能完成。 然而,我必须等待2分钟以上,它才能结束

有人能告诉我剩下的时间都到哪里去了吗?我使用的是Oracle SQL dev,但它似乎不会在其余时间处于空闲状态,该过程似乎锁定了相应的表:(

提前非常感谢您的启发

编辑:再次感谢您的输入:) 这是程序的精简代码,取决于要处理的项目数量,第一部分目前大约需要10到40秒,第二部分需要几毫秒。但是,该过程需要2到8分钟才能运行。 此外,包含要删除的数据的表似乎被锁定的时间比需要的时间稍长,从而导致插入延迟。 按计划作业启动它没有什么区别,顺便说一句,相同的行为

create or replace
procedure MY_PROCEDURE is
start_procedure number;
start_delete number;
end_procedure number;
begin

  start_procedure :=dbms_utility.get_time;

  begin
  -- stripped: doing some selects/updates here
  end;
  commit;

  start_delete :=dbms_utility.get_time ;

  begin
  -- stripped: cleanig up some other data here
  end;
  commit;
  end_procedure :=dbms_utility.get_time ;

  dbms_output.put_line('procedure took: '||to_char((end_procedure- start_procedure)/1000));
  dbms_output.put_line('updates took: '||to_char((start_delete- start_procedure)/1000));
  dbms_output.put_line('delete took: '||to_char((end_procedure-start_delete)/1000));

end;

我认为需要除以100,而不是1000(dbms_utility.get_time以厘米秒为单位给出时间)。这应该给你100秒,也就是2分钟

但是,如果您想知道2分钟的执行时间到哪里去了,并且取决于过程的复杂性,您可能希望:

  • 通过在过程运行之前和之后拍摄快照来收集statspack报告
  • 使用PL/SQL分层探查器()
如果有大量链接的PL/SQL过程调用,那么探查器可能会更好。如果存储过程中主要包含sql语句,则statspack报告会更好

以下是探查器输出的外观:

Sample Report

Function Elapsed Time (microsecs) Data sorted by Total Subtree Elapsed Time (microsecs)

2831 microsecs (elapsed time) & 12 function calls
Subtree     Ind%    Function    Descendant  Ind%    Calls   Ind%    Function Name
2831    100%    93  2738    96.7%   2   16.7%   __plsq_vm
2738    96.7%   310     2428    85.8%   2   16.7%   __anonymous_block
2428    85.8%   15  2413    85.2%   1   8.3%    HR.TEST.TEST (Line 1)
2413    85.2%   435     1978    69.9%   3   25.0%   HR.TEST.TEST.FOO (Line 3)
1978    69.9%   1978    0   0.0%    3   25.0%   HR.TEST.__static_sql_exec_line5 (Line 5)
0   0.0%    0   0   0.0%    1   8.3%    SYS.DBMS_HPROF.STOP_PROFILING (Line 53)

您的时间可能是由于SQL developer刷新您的屏幕时,java和数据库之间有大量的上下文切换。要测试这一点,请在SQLPlus中再次运行测试。要修复此问题,请进入工具>首选项>数据库>高级参数,并将SQL数组获取大小提高到150到500之间的某个值,并且(如果您有合适的驱动程序)勾选“使用OCI/厚驱动程序”框

如果您有合适的PERM(如果没有,请向您的dba寻求帮助),也许您可以查询以下视图:

V$SESSION_WAIT
V$SYSTEM_EVENT
然后可以检查结果

这里($session_wait.htm)*描述了如何读取输出以及其中的事件


*您必须复制url,因为$会弄乱链接。

那么是这样的吗

CREATE PROCEDURE ...
AS
DECLARE some stuff
BEGIN
    print time
    do stuff
    COMMIT
    print time
END
我对Oracle的事务范例了解不多,但我想知道,在过程完成之前,过程中的提交是否真的没有任何效果,而过程直到结束时才完成。此时,提交事务的实际过程开始了,如果涉及到触发器和引用完整性约束,则可能需要很长时间

这种行为类似于可延迟的初始延迟引用完整性约束的行为


我怀疑建议的系统表查询会告诉您,或者您可以尝试在交互式会话中单步执行“do stuff”步骤,看看会发生什么。

声明部分中可能有一些内容需要很长时间才能执行。您能提供存储过程的代码吗?

我不熟悉pl/sql,但有没有办法在它运行时暂停或中断它

当它浪费时间时,你击中它的几率等于它浪费时间的百分比,因此你可能需要多次阻止它,以便在行动中抓住它。通常问题是在调用堆栈中间的某个地方。如果可以替换出现在多个堆栈样本上的任何内容,都可以节省大量时间


该程序的作用是什么? 一种可能的解释是DBMS_输出。 如果在SQL*Plus上执行SET SERVEROUTPUT on,则在执行语句后,客户端将“幕后”获取使用DBMS_OUTPUT.PUT_行缓冲的任何信息。我猜SQL开发者也会这么做

因此,如果大量内容被推送到DBMS_输出,那么过程的执行可能会很快,但幕后收集可能会占用时间(特别是在网络速度较慢的情况下)

SQL*Plus中的另一个技巧是您可以 设置定时(将自动显示语句的运行时间) 和 将时间设置为ON(在SQL提示符中显示时间)

所以试试看

SET SERVEROUTPUT OFF
SET TIMING ON
SET TIME ON
DBMS_MONITOR.DATABASE_TRACE_ENABLE(TRUE);
exec stored_proc;
disconn
看看结果。我不希望看到任何时间下落不明。也就是说,客户应该报告整整两分钟的时间。
假设是这样,我将使用trace(DBMS_MONITOR命令)并对结果运行tkprof,以查看这2分钟的原因。

如果您将对DBMS_utility.get_time的调用替换为以下消息:

dbms_output.put_line ('start procedure: ' || to_char(sysdate, HH24:MI:SS'));
然后调用如下过程:

dbms_output.put_line ('before procedure: ' || to_char(sysdate, HH24:MI:SS'));
exec my_procedure;
dbms_output.put_line ('after procedure: ' || to_char(sysdate, HH24:MI:SS'));

然后,丢失时间发生的地方就会出现。

问题解决了,但我仍然不明白

泄漏是由另一个过程调用的另一个过程中隐藏的错误select语句引起的。我优化了它,现在它运行起来很有魅力

我发现了艰难的道路,逐行评论。。。试啊试啊

然而,我仍然想知道为什么时间戳是绝对不准确的。这很容易让人误解,花了我不少时间。。。 那么,我创建时间戳的方式有什么问题吗

如果有人有这方面的消息,我很高兴听到


感谢大家在这个问题上的帮助。

在DBMS\u输出语句中,将结果除以1000。根据我在dbms_实用程序中找到的所有Oracle文档,get_time函数以100秒为单位测量时间,而不是1000秒

因此,当您显示10到40秒时,它是actu