Oracle 使用dbms_profiler统计存储过程每步执行时间

最近和优化团队的专家学到一个很有意义的内置包:dbms_profiler,专门用于分析Oracle存储过程中的各段代码的时间开销情况,从而快速找到性能瓶颈的步骤。

 

一、 sys创建dbms_profiler

conn /as sysdba
desc dbms_profiler    --先确认dbms_profiler包是否存在,如果不存在则通过下面的方式创建
@?/rdbms/admin/profload.sql

主要函数:

  • start_profiler 启动对该程式监控
  • stop_profiler 结束对该程式监控

 

二、 创建profiler用户和对象

conn / as sysdba;
CREATE USER profiler IDENTIFIED BY profiler;
grant connect,resource to profiler;
conn profiler/profiler;
@?/rdbms/admin/proftab.sql
GRANT SELECT ON plsql_profiler_runnumber TO PUBLIC;
GRANT SELECT,INSERT,UPDATE,DELETE ON plsql_profiler_data TO PUBLIC;
GRANT SELECT,INSERT,UPDATE,DELETE ON plsql_profiler_units TO PUBLIC;
GRANT SELECT,INSERT,UPDATE,DELETE ON plsql_profiler_runs TO PUBLIC;
-- 建同义词
CREATE PUBLIC SYNONYM plsql_profiler_runnumber FOR profiler.plsql_profiler_runnumber;
CREATE PUBLIC SYNONYM plsql_profiler_runs FOR profiler.plsql_profiler_runs;
CREATE PUBLIC SYNONYM plsql_profiler_units FOR profiler.plsql_profiler_units;
CREATE PUBLIC SYNONYM plsql_profiler_data FOR profiler.plsql_profiler_data;

备注:

  • plsql_profiler_runs:prof运行信息
  • plsql_profiler_units:prof每个单元信息
  • plsql_profiler_data:prof每个单元的详细数据
  • plsql_profiler_runnumber:用来生成prof唯一运行编号的序列

 

三、 使用dbms_profiler收集信息

假设要对下面这样的一个存储过程进行分析

CREATE OR REPLACE procedure sp_profiler_test1
as
begin
   for x in 1..10000
   loop
       insert into t_t1 values(x);
   end loop;
   commit;
end sp_profiler_test1;
/

收集该存储过程执行信息方法如下:

set serverout on;
 DECLARE
    v_run_number   integer;
    v_temp1        integer;
 BEGIN
    --启动profiler
    sys.DBMS_PROFILER.start_profiler (run_number => v_run_number);
    --显示当前跟踪的运行序号(后面查询要用)
    DBMS_OUTPUT.put_line ('run_number:' || v_run_number);
    --运行要跟踪的PLSQL
    sp_profiler_test1;   --前一步创建的测试样例存储过程
    --停止profiler
    sys.DBMS_PROFILER.stop_profiler;
 END;

 

四、 查询并分析结果

set linesize 1000
col text format a60
SELECT   d.line#,                      --代码行号
    s.text,                            --源代码
       d.total_time,                   --总共运行时间(单位10亿分之一秒,即10的-9次方。)
       d.total_occur,                  --总共运行次数
       d.min_time,                     --最小运行时间
       d.max_time                      --最大运行时间
    FROM   plsql_profiler_data d, sys.all_source s, plsql_profiler_units u
   WHERE       d.runid = 2             --运行号(上一步执行相关过程时显示号码)
    and u.unit_name = 'SP_PROFILER_TEST1'        --单元名,即被测试的存储过程名
       AND u.runid = d.runid
    AND d.unit_number = u.unit_number
    AND d.total_occur <> 0
    AND s.TYPE(+) = u.unit_type
    AND s.owner(+) = u.unit_owner
    AND s.name(+) = u.unit_name
    AND d.line# = NVL (s.line, d.line#)
   ORDER BY  d.total_time desc, u.unit_number, d.line#;

示例查询结果如下:

     LINE# TEXT                                   TOTAL_TIME TOTAL_OCCUR   MIN_TIME   MAX_TIME
---------- -------------------------------------- ---------- ----------- ---------- ----------
         6        insert into t_t1 values(x);      150147563       10000      13108    3831882
         4    for x in 1..10000                       613220       10001         26       7514
         8    commit;                                  75630           1      75630      75630
         9 end sp_profiler_test1;                       1683           1       1683       1683

Elapsed: 00:00:01.39
  • LINE#:对应TEXT的语句在存储过程的第几行
  • TOTAL_TIME:执行的总时间(单位ns)
  • TOTAL_OCCUR:执行的次数
  • MIN_TIME:最短单次的运行时间(单位ns)
  • MAX_TIME:最长单次的运行时间(单位ns)

 

另附几个plsql相关sql

查询plsql执行时间占整个数据库执行时间比重

col db_time_secs format 999,999,999.99
col plsql_time_secs format 999,999,999.99
col pct_plsql_time format 99.99
col execs heading "Execs"
col text heading "Line text"
set lines 100
set pages 10000

set echo on
WITH plsql_times
       AS (SELECT SUM (CASE stat_name 
                            WHEN 'DB time' 
                            THEN value/1000000 END) AS db_time,
                  SUM(CASE stat_name
                           WHEN 'PL/SQL execution elapsed time'
                           THEN value / 1000000 END) AS plsql_time
             FROM v$sys_time_model
            WHERE stat_name IN ('DB time', 
                             'PL/SQL execution elapsed time'))
SELECT ROUND (db_time, 2) db_time_secs,
       ROUND (plsql_time, 2) plsql_time_secs,
       ROUND (plsql_time * 100 / db_time, 2) pct_plsql_time
  FROM plsql_times

通过v$sql获取所用时间详细数字,包含plsql执行时间、plsql占总sql执行时间比例、语句占数据库中所有plsql开销比例

set lines 100
set pages 1000
col sql_text format a30 heading "SQL Text"
col elapsed_ms format 9999999 heading "Total|time ms"
col plsql_ms format 99999999 heading "PLSQL|time ms"
col pct_plsql format 99.99 heading "Pct|PLSQL"
col pct_total_plsql format 99.99 heading "PCT of|Tot PLSQL"
set echo on 

SELECT sql_id,
       SUBSTR (sql_text, 1, 150) AS sql_text,
       ROUND (elapsed_time / 1000) AS elapsed_ms,
       ROUND (plsql_exec_time / 1000) plsql_ms,
       ROUND (plsql_exec_time * 100 / elapsed_time, 2) pct_plsql,
       ROUND (plsql_exec_time * 100 / SUM (plsql_exec_time) OVER (), 2)
          pct_total_plsql
  FROM v$sql
 WHERE plsql_exec_time > 0 AND elapsed_time > 0
ORDER BY plsql_exec_time DESC
    原文作者:Hehuyi_In
    原文地址: https://blog.csdn.net/Hehuyi_In/article/details/107771428
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞