目的: 调查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