使用dbms_profiler 调试PL/SQL 性能

目的: 调查PL/SQL(8.1级以上)的性能
参考文档:
Performance of New PL/SQL Features (Doc ID 104377.1)
Using DBMS_PROFILER (Doc ID 97270.1)
https://docs.oracle.com/cd/E11882_01/appdev.112/e40758/d_profil.htm#ARPLS67481

-- 安装
在sys账号下执行
$ORACLE_HOME/rdbms/admin/profload.sql    -- (默认是安装的,10g之前的版本没有安装,需要安装下)
在测试的用户账户下创建表
$ORACLE_HOME/rdbms/admin/proftab.sql

测试过程
启动profiling ,向dept表插入数据,产生跟踪信息(dbms_profiler.start_profile返回一个runid,用来查询profiler表)
运行要profiled的PL/SQL代码
停止Profiling。

-- 可能会需要授予权限  grant select on sys.v_$timer to ;


-- 创建要进行profile的案例

CREATE OR REPLACE PROCEDURE
SET_DNAME
(
  n_deptno IN NUMBER,
  n_dname OUT VARCHAR2
)
AS
BEGIN
  IF
    n_deptno > 100
  THEN
    n_dname := 'Large';
  ELSE
    n_dname := 'Small';
  END IF;
END SET_DNAME;
/

CREATE OR REPLACE PACKAGE TEST4 AS
PROCEDURE MAIN (n_deptno IN NUMBER, n_dname OUT VARCHAR2);
END;
/

CREATE OR REPLACE PACKAGE BODY TEST4
AS
PROCEDURE
DUMMY_PROC
(
  dept#  IN  NUMBER,
  count# OUT NUMBER
)
AS
BEGIN
  SELECT count(*) INTO count# FROM EMP WHERE DEPTNO= MOD(dept#,4)*10;
END dummy_proc;

PROCEDURE
MAIN
(
  n_deptno IN  NUMBER,
  n_dname  OUT VARCHAR2
)
IS
  count#     NUMBER;
  start_time NUMBER;
  end_time   NUMBER;
BEGIN
  SELECT HSECS INTO start_time FROM V$TIMER;
  SET_DNAME(n_deptno, n_dname);
  FOR i IN 1 .. 200 LOOP
    DUMMY_PROC( i, count#);
  END LOOP; -- e loop
  -- Placeholder
  SELECT HSECS INTO end_time FROM V$TIMER;
END MAIN;
END TEST4;
/

CREATE OR REPLACE TRIGGER
TRIG_IF
BEFORE INSERT ON DEPT
FOR EACH ROW
BEGIN
  TEST4.MAIN(:NEW.DEPTNO, :NEW.DNAME);
END;
/

--启动profiling,对表DEPT插入数据,产生profiling trace数据

SET SERVEROUTPUT ON
DECLARE
  v_run_id    PLS_INTEGER;
  v_ret_value PLS_INTEGER;
BEGIN
  v_ret_value := DBMS_PROFILER.START_PROFILER('TEST PROFILER','SAMPLE PROFILER',v_run_id);
EXCEPTION WHEN OTHERS THEN
  DBMS_OUTPUT.PUT_LINE('Error while starting the profiler :' || SQLERRM);
END;
/


SYS@test>SET SERVEROUTPUT ON
DECLARE
  v_run_id    PLS_INTEGESYS@test>  2  R;
  3    v_ret_value PLS_INTEGER;
B  4  EGIN
  5    v_ret_value := DBMS_PROFILER.START_PROFILER('TEST PROFILER','SAMPLE PROFILER',v_run_id);
EX  6  CEPTION WHEN OTHERS THEN
    7  DBMS_OUTPUT.PUT_LINE('Error while starting the profiler :' || SQLERRM);
E  8  ND;
  9  /

PL/SQL procedure successfully completed.

SYS@test>



INSERT INTO SCOTT.DEPT (DEPTNO) VALUES (99);

BEGIN
  DBMS_PROFILER.STOP_PROFILER;
EXCEPTION WHEN OTHERS THEN
  DBMS_OUTPUT.PUT_LINE('Error while stopping the profiler :' || SQLERRM);
END;
/


SYS@test>INSERT INTO SCOTT.DEPT (DEPTNO) VALUES (99);

1 row created.

SYS@test>BEGIN
  2    DBMS_PROFILER.STOP_PROFILER;
  3  EXCEPTION WHEN OTHERS THEN
   4   DBMS_OUTPUT.PUT_LINE('Error while stopping the profiler :' || SQLERRM);
  5  END;
  6  /

PL/SQL procedure successfully completed.

SYS@test>

-- 查看profiler 数据

SELECT RUNID, TO_CHAR(RUN_DATE,'DD-MON-YYYY HH24:MI:SS'), RUN_COMMENT FROM PLSQL_PROFILER_RUNS; 

SYS@test>SELECT RUNID, TO_CHAR(RUN_DATE,'DD-MON-YYYY HH24:MI:SS'), RUN_COMMENT FROM PLSQL_PROFILER_RUNS;

     RUNID TO_CHAR(RUN_DATE,'DD-MON-YYYY
---------- -----------------------------
RUN_COMMENT
--------------------------------------------------------------------------------
         1 03-AUG-2020 09:21:59
TEST PROFILER

         2 03-AUG-2020 10:45:35
TEST PROFILER


SYS@test>

-- 根据runid查看各个单元的执行时间等等。

COLUMN UNIT_NAME FORMAT A15
COLUMN OCCURED   FORMAT 999999
COLUMN LINE#     FORMAT 99999
COLUMN TOT_TIME  FORMAT 999.999999

SELECT U.UNIT_NAME, D.LINE#, D.TOTAL_OCCUR OCCURED, (D.TOTAL_TIME/1000000000) TOT_TIME,
(D.MIN_TIME/1000000000) MIN_TIME, (D.MAX_TIME/1000000000) MAX_TIME
FROM PLSQL_PROFILER_UNITS U, PLSQL_PROFILER_DATA D
WHERE D.RUNID = U.RUNID
AND D.UNIT_NUMBER = U.UNIT_NUMBER
AND D.TOTAL_OCCUR >0
AND U.RUNID = 2
ORDER BY U.UNIT_NUMBER, D.LINE#;

SYS@test>SELECT U.UNIT_NAME, D.LINE#, D.TOTAL_OCCUR OCCURED, (D.TOTAL_TIME/1000000000) TOT_TIME,
(  2  D.MIN_TIME/1000000000) MIN_TIME, (D.MAX_TIME/1000000000) MAX_TIME
F  3  ROM PLSQL_PROFILER_UNITS U, PLSQL_PROFILER_DATA D
WH  4  ERE D.RUNID = U.RUNID
A  5  ND D.UNIT_NUMBER = U.UNIT_NUMBER
  6  AND D.TOTAL_OCCUR >0
AN  7  D U.RUNID = 2
OR  8  DER BY U.UNIT_NUMBER, D.LINE#;

UNIT_NAME        LINE# OCCURED    TOT_TIME   MIN_TIME   MAX_TIME
--------------- ------ ------- ----------- ---------- ----------
DBMS_PROFILER       67       1     .000020 .000019996 .000019996
DBMS_PROFILER       80       1     .000000          0          0
DBMS_PROFILER       81       1     .000000          0          0
DBMS_PROFILER       96       1     .000002 .000001999 .000001999
DBMS_PROFILER      152       1     .000002 .000000999 .000000999
DBMS_PROFILER      157       1     .000001 .000000999 .000000999
          8       1     .000002 .000001999 .000001999
          1       2     .000076 .000001999 .000029994
DBMS_OUTPUT        182       5     .000003          0 .000000999
DBMS_OUTPUT        186       5     .000005 .000000999 .000000999
DBMS_OUTPUT        191       5     .000010 .000001999 .000001999

UNIT_NAME        LINE# OCCURED    TOT_TIME   MIN_TIME   MAX_TIME
--------------- ------ ------- ----------- ---------- ----------
DBMS_OUTPUT        192       5     .000010 .000001999 .000001999
DBMS_OUTPUT        194       5     .000010 .000001999 .000001999
DBMS_OUTPUT        197       5     .000004          0 .000000999
DBMS_OUTPUT        200       5     .000012 .000001999 .000002999
DBMS_OUTPUT        201       5     .000003 .000000999 .000000999
DBMS_OUTPUT        204       5     .000007 .000000999 .000001999
DBMS_OUTPUT        205       5     .000010 .000000999 .000002999
          1       2     .000082 .000001999 .000036993
TRIG_IF              2       2     .001563 .000002999 .001537715
TRIG_IF              3       2     .000005 .000001999 .000002999
TEST4                3     400     .000212 .000000999 .000001999

UNIT_NAME        LINE# OCCURED    TOT_TIME   MIN_TIME   MAX_TIME
--------------- ------ ------- ----------- ---------- ----------
TEST4               10     400     .000000          0          0
TEST4               11     400     .013225 .000022995 .001799667
TEST4               12     400     .000213          0 .000001999
TEST4               14       2     .000006 .000000999 .000002999
TEST4               24       2     .000000          0          0
TEST4               25       2     .003270 .000083984  .00318641
TEST4               26       2     .000877 .000000999 .000762858
TEST4               27     402     .000113 .000000999 .000001999
TEST4               28     400     .000426          0 .000003999
TEST4               29       2     .000000          0          0
TEST4               31       2     .000136 .000065987 .000069987

UNIT_NAME        LINE# OCCURED    TOT_TIME   MIN_TIME   MAX_TIME
--------------- ------ ------- ----------- ---------- ----------
TEST4               32       2     .000005 .000001999 .000002999
SET_DNAME           10       2     .000001          0 .000000999
SET_DNAME           14       2     .000013 .000005998 .000006998
SET_DNAME           16       2     .000002 .000000999 .000000999
          1       2     .000078 .000001999 .000034993
          1       2     .000087 .000001999 .000038992
          1       2     .000082 .000000999 .000039992
          2       2     .000018 .000001999 .000015997

41 rows selected.

SYS@test>

-- 查看每一行执行的时间

COLUMN UNIT_NAME FORMAT A15
COLUMN OCCURRED  FORMAT 999999
COLUMN LINE      FORMAT 9999
COLUMN TOT_TIME  FORMAT 999.999999
COLUMN TEXT      FORMAT A46

SELECT P.UNIT_NAME, P.OCCURRED, P.TOT_TIME, P.LINE# LINE, SUBSTR(S.TEXT, 1,75) TEXT
FROM (SELECT U.UNIT_NAME, D.TOTAL_OCCUR OCCURRED, (D.TOTAL_TIME/1000000000) TOT_TIME,
D.LINE# FROM PLSQL_PROFILER_UNITS U, PLSQL_PROFILER_DATA D
WHERE D.RUNID=U.RUNID AND D.UNIT_NUMBER = U.UNIT_NUMBER AND D.TOTAL_OCCUR >0
AND U.RUNID= 2) P,USER_SOURCE S
WHERE P.UNIT_NAME = S.NAME(+) AND P.LINE# = S.LINE (+)
ORDER BY P.UNIT_NAME, P.LINE#;



SYS@test>SELECT P.UNIT_NAME, P.OCCURRED, P.TOT_TIME, P.LINE# LINE, SUBSTR(S.TEXT, 1,75) TEXT
  2  FROM (SELECT U.UNIT_NAME, D.TOTAL_OCCUR OCCURRED, (D.TOTAL_TIME/1000000000) TOT_TIME,
  3  D.LINE# FROM PLSQL_PROFILER_UNITS U, PLSQL_PROFILER_DATA D
W  4  HERE D.RUNID=U.RUNID AND D.UNIT_NUMBER = U.UNIT_NUMBER AND D.TOTAL_OCCUR >0
A  5  ND U.RUNID= 2) P,USER_SOURCE S
  6  WHERE P.UNIT_NAME = S.NAME(+) AND P.LINE# = S.LINE (+)
O  7  RDER BY P.UNIT_NAME, P.LINE#;

UNIT_NAME       OCCURRED    TOT_TIME  LINE TEXT
--------------- -------- ----------- ----- ----------------------------------------------
            2     .000076     1
            2     .000082     1
            2     .000087     1
            2     .000078     1
            2     .000082     1
            2     .000018     2
            1     .000002     8
DBMS_OUTPUT            5     .000003   182
DBMS_OUTPUT            5     .000005   186
DBMS_OUTPUT            5     .000010   191
DBMS_OUTPUT            5     .000010   192

UNIT_NAME       OCCURRED    TOT_TIME  LINE TEXT
--------------- -------- ----------- ----- ----------------------------------------------
DBMS_OUTPUT            5     .000010   194
DBMS_OUTPUT            5     .000004   197
DBMS_OUTPUT            5     .000012   200
DBMS_OUTPUT            5     .000003   201
DBMS_OUTPUT            5     .000007   204
DBMS_OUTPUT            5     .000010   205
DBMS_PROFILER          1     .000020    67
DBMS_PROFILER          1     .000000    80   pragma exception_init(profiler_error, -6528)
                                           ;

DBMS_PROFILER          1     .000000    81

UNIT_NAME       OCCURRED    TOT_TIME  LINE TEXT
--------------- -------- ----------- ----- ----------------------------------------------
DBMS_PROFILER          1     .000002    96   --                run number. This allows th
                                           e caller to determine what th

DBMS_PROFILER          1     .000002   152
DBMS_PROFILER          1     .000001   157   --
SET_DNAME              2     .000001    10     n_deptno > 100
SET_DNAME              2     .000013    14     n_dname := 'Small';
SET_DNAME              2     .000002    16 END SET_DNAME;
TEST4                400     .000212     3 PROCEDURE
TEST4                400     .000212     3 END;
TEST4                400     .000000    10 BEGIN

UNIT_NAME       OCCURRED    TOT_TIME  LINE TEXT
--------------- -------- ----------- ----- ----------------------------------------------
TEST4                400     .013225    11   SELECT count(*) INTO count# FROM SCOTT.EMP W
                                           HERE DEPTNO= MOD(dept#,4)*10;

TEST4                400     .000213    12 END dummy_proc;
TEST4                  2     .000006    14 PROCEDURE
TEST4                  2     .000000    24 BEGIN
TEST4                  2     .003270    25   SELECT HSECS INTO start_time FROM V$TIMER;
TEST4                  2     .000877    26   SET_DNAME(n_deptno, n_dname);
TEST4                402     .000113    27   FOR i IN 1 .. 200 LOOP
TEST4                400     .000426    28     DUMMY_PROC( i, count#);
TEST4                  2     .000000    29   END LOOP; -- e loop

UNIT_NAME       OCCURRED    TOT_TIME  LINE TEXT
--------------- -------- ----------- ----- ----------------------------------------------
TEST4                  2     .000136    31   SELECT HSECS INTO end_time FROM V$TIMER;
TEST4                  2     .000005    32 END MAIN;
TRIG_IF                2     .001563     2 TRIG_IF
TRIG_IF                2     .000005     3 BEFORE INSERT ON scott.DEPT

42 rows selected.

SYS@test>

--- 备注,也可以将测试的存储过程放在dbms_profiler.start_profiler和dbms_profiler.stop_profiler之间。

declare 
    err  number;
begin
    err:=dbms_profiler.start_profiler('testprofiler');
    test_proc(10);   -- 要profiler的语句	
	err:=dbms_profiler.stop_profiler;
end;

/

END

你可能感兴趣的:(性能优化)