如果需要针对PL/SQL进行跟踪,找出最耗时间的语句块,可以使用oracle提供的DBMS_PROFILER进行跟踪。
检查DBMS_PROFILER包是否安装 sys@ORCL> desc dbms_profiler
如果没有安装可以运行$ORACLE_HOME/rdbms/admin/profload.sql 脚本安装
默认情况下DBMS_PROFILER包已经安装,但是想要在某个schema下使用dbms_profiler,需要创建相应的表。
sql在$ORACLE_HOME/rdbms/admin/proftab.sql 执行即可
desc dbms_profiler 可以看见dbms_profiler 包已经安装,然后创建一个用于存放跟踪信息的用户,及其prof表和序列的同义词
sys@ORCL> CREATE USER profiler IDENTIFIED BY profiler;
用户已创建。
sys@ORCL> grant connect,resource to profiler;
授权成功。
sys@ORCL> CREATE PUBLIC SYNONYM plsql_profiler_runs FOR profiler.plsql_profiler_runs;
同义词已创建。
sys@ORCL> CREATE PUBLIC SYNONYM plsql_profiler_units FOR profiler.plsql_profiler_units;
同义词已创建。
sys@ORCL> CREATE PUBLIC SYNONYM plsql_profiler_data FOR profiler.plsql_profiler_data;
同义词已创建。
sys@ORCL> CREATE PUBLIC SYNONYM plsql_profiler_runnumber FOR profiler.plsql_profiler_runnumber;
同义词已创建。
sys@ORCL> conn profiler/profiler
已连接。
profiler@ORCL> @?/rdbms/admin/proftab.sql
... ...
profiler@ORCL> GRANT SELECT ON plsql_profiler_runnumber TO PUBLIC;
授权成功。
profiler@ORCL> GRANT SELECT,INSERT,UPDATE,DELETE ON plsql_profiler_data TO PUBLIC;
授权成功。
profiler@ORCL> GRANT SELECT,INSERT,UPDATE,DELETE ON plsql_profiler_units TO PUBLIC;
授权成功。
profiler@ORCL> GRANT SELECT,INSERT,UPDATE,DELETE ON plsql_profiler_runs TO PUBLIC;
授权成功。
备注:
profiler@ORCL> select o.OBJECT_NAME,o.OBJECT_TYPE from user_objects o order by o.OBJECT_TYPE
2 /
OBJECT_NAME OBJECT_TYPE
------------------------------ -------------------
SYS_C0023499 INDEX
SYS_C0023502 INDEX
SYS_C0023497 INDEX
PLSQL_PROFILER_RUNNUMBER SEQUENCE
PLSQL_PROFILER_UNITS TABLE
PLSQL_PROFILER_DATA TABLE
PLSQL_PROFILER_RUNS TABLE
已选择7行。
清楚旧数据:
delete from profiler.plsql_profiler_data;
delete from profiler.plsql_profiler_units;
delete from profiler.plsql_profiler_runs;
u1@ORCL> conn u1/u1
已连接。
u1@ORCL> create table tab_test (a int);
表已创建。
u1@ORCL> CREATE OR REPLACE PROCEDURE sp_test AS
2 BEGIN
3 FOR I IN 1 .. 100000 LOOP
4 INSERT INTO tab_test VALUES (I);
5 END LOOP;
6 COMMIT;
7 END;
8 /
过程已创建。
u1@ORCL> DECLARE
2 v_run_number integer;
3 BEGIN
4 --启动profiler
5 sys.DBMS_PROFILER.start_profiler(run_number => v_run_number);
6 --显示当前跟踪的运行序号(后面查询要用)
7 DBMS_OUTPUT.put_line('run_number:' || v_run_number);
8 sp_test;跟踪的PLSQL
--运行要跟踪的PLSQL
9 sp_test;
10 --停止profiler
11 sys.DBMS_PROFILER.stop_profiler;
12 END;
13 /
run_number:2
PL/SQL 过程已成功完成。
--获得本次prof的基本运行信息:
u1@ORCL> select runid,run_owner,run_date,run_total_time from plsql_profiler_runs where runid = 2;
RUNID RUN_OWNER RUN_DATE RUN_TOTAL_TIME
---------- -------------------------------- ------------------- --------------
2 U1 2014-01-19 19:37:47 130000000
--根据运行号和单元名(即测试的存储过程名)获得本次prof的单元信息:
u1@ORCL> select unit_number,unit_type,unit_owner,unit_name,unit_timestamp,total_time from plsql_profiler_units where runid = 2 and unit_name = 'SP_TEST';
UNIT_NUMBER UNIT_TYPE UNIT_OWNER UNIT_NAME UNIT_TIMESTAMP TOTAL_TIME
----------- --------------- ---------- --------------- ------------------- ----------
2 PROCEDURE U1 SP_TEST 2014-01-19 19:35:23 0
--根据运行号获得该存储过程每行运行的统计信息:
u1@ORCL> select runid,unit_number,line#,total_occur,total_time,min_time,max_time from plsql_profiler_data where runid = 2;
RUNID UNIT_NUMBER LINE# TOTAL_OCCUR TOTAL_TIME MIN_TIME MAX_TIME
---------- ----------- ---------- ----------- ---------- ---------- ----------
2 1 1 0 0 0 0
2 1 5 0 4080 4080 4080
2 1 7 1 77535 77535 77535
2 1 9 2 32646 2040 30606
2 1 11 1 3060 3060 3060
2 1 12 0 0 0 0
2 2 1 0 3060 3060 3060
2 2 3 101 136707 1020 2040
2 2 4 100 11547733 49990 5504021
2 2 6 1 106101 106101 106101
2 2 7 1 3060 3060 3060
已选择11行。
以上信息都不怎么直观,通过下面的sql更加直观展示:
u1@ORCL> SELECT d.line#, --代码行号
2 s.text, --源代码
3 round(d.total_time / 1000000000, 2) total_time, --总共运行时间(单位秒)
4 d.total_occur, --总共运行次数
5 round(d.min_time / 1000000000, 2) min_time, --最小运行时间
6 round(d.max_time / 1000000000, 2) max_time --最大运行时间
7 FROM plsql_profiler_data d, sys.all_source s, plsql_profiler_units u
8 WHERE d.runid = 7 --运行号
9 and u.unit_name = 'SP_TEST' --单元名,即被测试的存储过程名
10 AND u.runid = d.runid
11 AND d.unit_number = u.unit_number
12 AND d.total_occur <> 0
13 AND s.TYPE(+) = u.unit_type
14 AND s.owner(+) = u.unit_owner
15 AND s.name(+) = u.unit_name
16 AND d.line# = NVL(s.line, d.line#)
17 ORDER BY u.unit_number, d.line#;
LINE# TEXT TOTAL_TIME TOTAL_OCCUR MIN_TIME MAX_TIME
---------- ------------------------------------------------------------ ---------- ----------- ---------- ----------
1 PROCEDURE sp_test AS 0 1 0 0
2 BEGIN 0 1 0 0
3 FOR I IN 1 .. 100000 LOOP .15 100001 0 0
4 INSERT INTO tab_test VALUES (I); 6.38 100000 0 .34
5 END LOOP; 0 1 0 0
6 COMMIT; 0 1 0 0
7 END; 0 1 0 0
已选择7行。
更多内容参考:
使用 DBMS_PROFILER 定位 PL/SQL 瓶颈代码
http://blog.csdn.net/leshami/article/details/12100235
对比 PL/SQL profiler 剖析结果
http://blog.csdn.net/leshami/article/details/12110195
使用PL/SQL Developer剖析PL/SQL代码
http://blog.csdn.net/leshami/article/details/12187115
PL/SQL Profiler 剖析报告生成html
http://blog.csdn.net/leshami/article/details/12426469