dbms_profiler启动失败主因是权限不足或未安装,需dba授权execute及select权限并运行profload.sql;数据需flush_data才写入,否则查不到;分析时应关注调用频次高、总耗时大的自有代码行,而非仅看单次耗时最长者。
dbms_profiler 启动失败报 ora-20000 或权限不足
启动 dbms_profiler.start_profiler 时直接报错,常见原因是当前用户没被显式授予执行权限,或未安装 profiler 相关对象。oracle 不默认启用该包,即使有 dba 角色也不自动包含它。
- 用
SELECT * FROM all_objects WHERE object_name = 'DBMS_PROFILER'确认包是否存在;不存在需由 DBA 运行$ORACLE_HOME/rdbms/admin/profload.sql - 确认权限:DBA 需执行
GRANT EXECUTE ON DBMS_PROFILER TO your_user,且必须包含GRANT SELECT ON plsql_profiler_* TO your_user(共三张表) - 别依赖角色继承——
EXECUTE ANY PROCEDURE不等价于对DBMS_PROFILER的 EXECUTE 权限
运行后查不到数据:profiler 数据没入库或被覆盖
DBMS_PROFILER.STOP_PROFILER 只是结束采集,数据存在 session 级缓存里,必须显式调用 DBMS_PROFILER.FLUSH_DATA 才写入数据字典表。很多人漏这步,导致查 plsql_profiler_runs 是空的。
- 必须按顺序调用:
START_PROFILER→ 执行目标 PL/SQL →FLUSH_DATA→STOP_PROFILER - 如果同一 session 多次运行 profiler,不
FLUSH_DATA就START_PROFILER,前一次数据会被丢弃(不是追加) - 检查
plsql_profiler_data行数是否远小于预期——可能因异常退出没走到FLUSH_DATA,建议用匿名块包裹并加EXCEPTION WHEN OTHERS THEN DBMS_PROFILER.FLUSH_DATA; RAISE;
看懂 profiler 输出:关键字段和过滤技巧
瓶颈不在总耗时长的函数,而在 TOTAL_OCCURS 高 + TOTAL_TIME 单位为纳秒但数值大、且 UNIT_OWNER/UNIT_NAME 指向你自己的包或过程——这才是真热点。
-
LINE#是源码行号,但注意:PL/SQL 编译后行号可能偏移,优先对照UNIT_NAME和上下文逻辑定位 - 别只看
TOTAL_TIME最大值——循环体内的某行被调用 10 万次,每次 100ns,总时间就占 10ms;而一个外部 HTTP 调用只 1 次但耗 500ms,后者更该优化 - 常用过滤:
SELECT * FROM plsql_profiler_data d JOIN plsql_profiler_units u USING (unit_number) WHERE u.unit_name = 'YOUR_PKG' ORDER BY d.total_time DESC
替代方案比 profiler 更轻量:DBMS_HPROF 和实时 ASH
DBMS_PROFILER 需修改代码、启停、查表,对生产环境扰动大;且无法捕获 SQL 执行细节(比如绑定变量、实际执行计划)。遇到“PL/SQL 快但整体慢”,大概率是隐式 SQL 拖累,profiler 根本不显示。
-
DBMS_HPROF.ANALYZE生成树状调用报告,开销更低,支持 HTML 输出,适合快速抓一次调用栈 - 真要盯生产,直接查
V$ACTIVE_SESSION_HISTORY(ASH):用session_id+plsql_entry_object_id关联DBA_OBJECTS,能定位到正在卡住的 PL/SQL 行,且含等待事件、SQL_ID - 如果只是想确认某段逻辑是否被高频调用,用
DBMS_APPLICATION_INFO.SET_MODULE打标 + AWR 报告更稳
profiler 不是银弹,它只告诉你“哪行代码被执行了多少次、花了多久”,但不会告诉你“为什么慢”——比如索引失效、锁争用、硬解析,这些得靠其他线索交叉验证。










