DBMS_PROFILER需先安装包、建表、赋权并同会话执行启停,否则报ORA-06528/ORA-04043;须SYS执行profload.sql装包,被测用户执行proftab.sql建表,START_PROFILER获取run_id后同会话运行代码并提交事务,再关联all_source查纳秒级耗时。
dbms_profiler 能给出每行 pl/sql 代码的执行次数和纳秒级耗时,但前提是它必须能“看到”你的代码——这要求你先装包、建表、赋权、再包裹执行,缺一不可;否则 start_profiler 会直接报 ora-06528 或 ora-04043。
检查并安装 DBMS_PROFILER 包(SYS 用户下)
很多 Oracle 实例(尤其是 10g 及更早版本)默认不带这个包。别跳过验证步骤:
- 先连
SYS AS SYSDBA执行DESC dbms_profiler—— 如果报ORA-04043: object dbms_profiler does not exist,说明没装 - 运行
@?/rdbms/admin/profload.sql(路径中的?会被自动替换为$ORACLE_HOME) - 注意:该脚本只创建包和同义词,不建数据表;且必须由
SYS执行,普通用户执行会失败
创建 profiler 数据表(目标用户下)
三张表(PLSQL_PROFILER_RUNS、PLSQL_PROFILER_UNITS、PLSQL_PROFILER_DATA)和一个序列(PLSQL_PROFILER_RUNNUMBER)必须由“将要运行被测代码”的用户自己执行脚本创建:
- 用待测代码所属用户(比如
SCOTT)登录,执行@?/rdbms/admin/proftab.sql - 如果该用户没有
CREATE TABLE权限,会报ORA-01031: insufficient privileges—— 此时需SYS先授CREATE TABLE,不能只给EXECUTE ON dbms_profiler - 执行成功后,立刻查
USER_TABLES确认三张表已存在,避免后续STOP_PROFILER后查不到数据
包裹待测代码并获取 run_id
START_PROFILER 返回一个 runid,它是后续查数据的唯一入口;硬编码字符串注释容易混淆,建议用变量捕获:
BEGIN DBMS_PROFILER.START_PROFILER(run_number => :run_id, run_comment => 'my_proc_v2_20260619'); -- 这里放你要测的 PL/SQL 块或调用存储过程 my_slow_procedure(); DBMS_PROFILER.STOP_PROFILER; END;
- 务必在同一个 session 中执行 start / 业务代码 / stop —— 跨 session 会导致数据写入失败或丢失
- 不要依赖
DBMS_PROFILER.FLUSH_DATA:它仅在异常中断时手动刷缓存用,正常流程不需要 - 如果被测代码含 DML,记得 commit;否则
PLSQL_PROFILER_DATA表可能因事务未结束而查不到记录
查询并解读 profiler 数据
核心是把 PLSQL_PROFILER_DATA 和源码行对齐。时间单位是纳秒,直接除以 1000000 得毫秒更直观:
SELECT d.line#, d.total_occur, ROUND(d.total_time/1000000, 2) ms,
s.text
FROM plsql_profiler_data d
JOIN plsql_profiler_units u ON d.runid = u.runid AND d.unit_number = u.unit_number
JOIN all_source s ON u.unit_name = s.name AND u.unit_owner = s.owner AND s.type = u.unit_type AND d.line# = s.line
WHERE d.runid = &your_run_id
AND s.owner = '&schema'
ORDER BY d.total_time DESC;- 重点看
total_time最高的几行——它们往往是循环体、隐式类型转换、或未走索引的 SQL - 如果某行
total_occur极高但单次min_time很低,说明是高频小操作,优化收益有限;反之,max_time显著高于avg_time可能暗示锁争用或临时空间不足 -
all_source是关键:确保你查的是当前编译版本的源码;如果过程刚改过但没 recompile,数据会对应旧行号
真正容易被忽略的是权限链和事务边界:PROFTAB.SQL 创建的表必须由被测用户拥有,DBMS_PROFILER 写数据时不会跨 schema 自动 resolve;另外,哪怕只差一次 commit,整个 run 的数据都可能卡在 UNDO 段里查不到。



















