如何分析Oracle存储过程的端到端性能

时间:2011-10-05 15:38:26

标签: performance oracle stored-procedures plsql oracle10g

我想知道我的存储过程从外部进程到达数据库的时间执行了多长时间,然后执行此操作直到数据库返回到进程并在此处说明了。

有一种简单的方法可以完成这项非常基本的任务吗?

当然,报告存储过程执行期间发生的事情以及存储过程花费多少时间来完成每项任务(插入,plsql字符串操作等)将是一个奖励,但我真的只想要一些简单的东西而且易于使用。 (并免费)

3 个答案:

答案 0 :(得分:6)

如果您使用的是Oracle 11g,那么您应该查看分层分析器DBMS_HPROF。这是一个工具,它将为您提供PL / SQL程序中所有节点的已用时间。顾名思义,它对于调用调用程序调用程序的程序特别有用。它还标识了与函数调用不同的SQL语句的时序。 Find out more

它是标准11g部署的一部分,因此是免费的。好吧,一旦你支付了许可费,它就是免费的:)

默认情况下,DBMS_HPROF程序包的权限不会授予任何一个。因此,您需要获得具有SYSDBA访问权限的人才能看到您。分析还需要创建一些表。这些事情都不应成为问题,但有时我知道它们是。


唉,你的早期版本。因此,只剩下DBMS_PROFILER,它自9i以来一直存在。这基本上适用于单个程序。它的主要缺点是我们只能在我们拥有CREATE特权的程序上使用它(即我们架构中的程序,除非我们有CREATE ANY PROCEDURE特权,这通常意味着是DBA)。此外,为了分析嵌入式SQL语句,我们需要使用DBMS_TRACE包。 Find out more.

答案 1 :(得分:3)

简单,最便宜的选择 您可以将事件记录到“调试”表并检查日志之间的持续时间,例如ex。 在插入到表a中之前记录事件,带有时间戳a到调试表中。 将带有时间戳b的表插入到表a中后记录事件。

如果你的存储过程超过5行,这有点费时,但它会帮助你。还要实现调试标志,因此当需要记录时间戳时,将过程顶部的标志设置为true,然后重新编译它。执行存储过程时,它将继续记录所有事件,完成调试后,将标志设置为false并重新编译。

答案 2 :(得分:0)

如果您希望将自己的时间间隔写入PL / SQL程序,则下面是我的模板代码。另外,这不需要您的DBA的帮助。我的DBA常常不愿给我更多访问权限。那样,我讨厌等待他们真正给我访问权限。

/* This procedure is simply an example of parsing out an Elapsed time into their individual time parts */
/*   In other words it provides to the user the elapsed time in hours : minutes : seconds . milliseconds */

DECLARE

  G_START_TIME1     NUMBER        := DBMS_UTILITY.GET_TIME;
  G_START_TIME2     NUMBER        := DBMS_UTILITY.GET_TIME;
  vG_ELAPSED_TIME   VARCHAR2(200);

  /* Variables below are used for storing Elapsed time. */
  RETVAL           NUMBER;
  hourss            NUMBER;
  minutess          NUMBER;
  secondss          NUMBER;
  millisecondss     NUMBER;
    n_hrs         NUMBER := 360000;
    n_mins        NUMBER := 6000;
    n_secs        NUMBER := 100;
    n_sixty       NUMBER := 60;
    n_thirty      NUMBER := 30;
    n_ten         NUMBER := 10;

  v_PrintTime     VARCHAR2(200);


  /* The procedure below is simply used to simulate the passage of time */
  PROCEDURE waste_time(pn_Seconds NUMBER) IS

  n_CentiSeconds  NUMBER  :=  pn_Seconds * 100;
  n_ProgramStart  NUMBER  := DBMS_UTILITY.GET_TIME; /* dbms_utility_get_time returns times in hundreds of a second */

  BEGIN
    WHILE DBMS_UTILITY.GET_TIME < n_ProgramStart + n_CentiSeconds
    LOOP
      null;
    END LOOP;
  END waste_time;

BEGIN

  G_START_TIME1   :=    -2019618227; --dbms_utility.get_time;

  --waste_time(1);
  --dbms_output.put_line('1 Second Wasted'|| chr(10));

  G_START_TIME2   :=    G_START_TIME1 + 366110; ---2019619227; --dbms_utility.get_time;

  dbms_output.put_line('Start_time: '||G_START_TIME1);
  dbms_output.put_line('End_time:   '||G_START_TIME2||chr(10));

  vG_ELAPSED_TIME :=  G_START_TIME2 - G_START_TIME1;
  millisecondss   :=  vG_ELAPSED_TIME * n_ten;
  secondss        :=  vG_ELAPSED_TIME / n_secs;
  minutess        :=  vG_ELAPSED_TIME / n_mins;
  hourss          :=  vG_ELAPSED_TIME / n_hrs;

  dbms_output.put_line('Total Time: '||millisecondss ||' Milliseconds');
  dbms_output.put_line('Total Time: '||vG_ELAPSED_TIME ||' Centiseconds');
  dbms_output.put_line('Total Time: '||secondss ||' Seconds');
  dbms_output.put_line('Total Time: '||minutess ||' Minutes');
  dbms_output.put_line('Total Time: '||hourss ||' Hours');

  millisecondss   :=  mod(vG_ELAPSED_TIME * n_ten, 1000);            /* Milliseconds into Seconds.  Returns left over millisedonds */
  secondss        :=  trunc(mod(vG_ELAPSED_TIME / n_secs, n_sixty)); /* Seconds into hours.  Returns how many seconds are left over */
  minutess        :=  trunc(mod(vG_ELAPSED_TIME / n_mins, n_sixty)); /* Seconds into hours.  Returns how many seconds are left over */
  hourss          :=  trunc(vG_ELAPSED_TIME / n_hrs);                /* Spit out hours only using just trunc here.  Since we don't need to build up Days we can leave this as is */

  v_PrintTime     :=  hourss ||':'|| minutess ||':'|| secondss ||'.'|| millisecondss;

  dbms_output.put_line(chr(10) ||'Elapsed Time: '|| v_PrintTime);


END;