不能。dbms_profiler仅记录pl/sql控制流耗时,不捕获嵌入sql的真实执行耗时;需结合v$session_wait、v$sql和explain plan分析i/o、锁、执行计划等深层原因。
dbms_profiler 能不能直接看出某行 sql 的执行耗时?
不能。dbms_profiler 只记录 pl/sql 控制流的耗时,比如 for 循环、if 判断、变量赋值这些语句的执行次数和相对时间片,但它不捕获嵌入其中的 sql 语句(如 select into、update)的真实执行耗时。你看到某行 line# 127 占总耗时 95%,那行代码本身可能只是一条 select emp_name into v_name from emp where id = p_id;——真正卡住的是背后这条 sql 的 i/o 等待或锁争用,dbms_profiler 不会告诉你这些。
启动前必须满足的三个硬性条件
漏掉任意一条,DBMS_PROFILER 就不会写入有效数据,查 PLSQL_PROFILER_DATA 会为空:
-
GRANT EXECUTE ON DBMS_PROFILER TO your_user;—— 权限缺失时START_PROFILER静默失败,无报错 - 目标存储过程必须用
DEBUG模式重编译:ALTER PROCEDURE your_proc COMPILE DEBUG;—— 否则行号映射错乱,line#对不上源码 - 启动、执行、停止、刷新必须在**同一会话**内完成:
DBMS_PROFILER.STOP_PROFILER后立即执行DBMS_PROFILER.FLUSH_DATA,否则数据滞留在 PGA 内存里没落库
查结果时为什么总找不到对应行号?
因为四张表必须严格关联,少一环就查不到数据:
- 先从
PLSQL_PROFILER_RUNS找到最新runid(注意status是FINISHED而非RUNNING) - 再用该
runid关联PLSQL_PROFILER_UNITS,确认unit_name和unit_type匹配你的存储过程名与类型(如PROCEDURE),拿到正确的unit_number - 最后用
runid + unit_number去PLSQL_PROFILER_DATA查line#和total_time—— 如果跳过中间这步,unit_number错了,line#就全对不上
常见错误是只查 PLSQL_PROFILER_DATA,却没验证 unit_number 是否来自你要分析的过程。
怎么判断哪一行才是真正瓶颈?
别只盯着 TOTAL_TIME 最高的那一行。重点看两个指标的组合:
-
TOTAL_OCCUR > 1且TOTAL_TIME / TOTAL_OCCUR > 0.01秒(即单次执行超 10ms)——说明是高频+慢操作,比如循环内没走索引的查询 -
TOTAL_OCCUR = 1但TOTAL_TIME极高(比如 8 秒)——大概率是某条隐式 SQL 卡住了,得提取出来单独跑EXPLAIN PLAN FOR - 注意
line#对应的是 PL/SQL 源码行,不是 SQL 文本行;如果是SELECT ... INTO,要把变量替换成字面量再分析执行计划
Oracle 12c+ 默认禁用 DBMS_PROFILER,且 PLSQL_CODE_TYPE = NATIVE 时它会完全失效——必须设为 INTERPRETED 并重编译,这点很容易被忽略。











