直接查V$SQL可快速获取共享池中最近慢SQL,但定位PL/SQL内具体慢行需用DBMS_PROFILER;其通过start_profiler→执行→stop_profiler→FLUSH_DATA流程记录每行代码的执行次数与纳秒级耗时,结合unit_name和line#精准定位瓶颈。
直接查 v$sql 就能拿到最近执行过的慢 sql,但前提是它还在共享池里;真要定位 pl/sql 块里哪一行 sql 慢,得用 dbms_profiler,否则只能靠猜。
查 V$SQL 快速捞出已执行的慢语句
Oracle 把最近执行过的 SQL 和耗时都记在 V$SQL 里,只要没被刷出共享池,就能查到。注意单位是微秒(elapsed_time),1 秒 = 1000000 微秒。
- 阈值别设太低——比如
elapsed_time > 500000(0.5 秒)可能捞出大量短平快语句,干扰判断 - 加
sql_text NOT LIKE 'SELECT * FROM V$%'过滤掉监控自身产生的查询 - 用
executions > 1排除一次性语句,聚焦高频慢 SQL - 如果查不到预期语句,大概率是已被老化淘汰,这时得换实时捕获手段
示例:
SELECT sql_id, sql_text, elapsed_time/1000000 AS sec, executions, buffer_gets FROM v$sql WHERE elapsed_time > 1000000 AND executions > 0 AND sql_text NOT LIKE 'SELECT%V$%' ORDER BY elapsed_time DESC FETCH FIRST 10 ROWS ONLY;
用 DBMS_PROFILER 定位 PL/SQL 内部慢 SQL 行号
存储过程或匿名块里嵌了多条 SQL,光看 V$SQL 不知道是哪条拖慢整体——DBMS_PROFILER 能记录每行代码的执行次数和耗时,精确到行号。
- 必须提前启用:运行
CALL dbms_profiler.start_profiler(run_comment => 'my_test'); - 执行完目标 PL/SQL 后立刻调用
dbms_profiler.stop_profiler(),否则数据不完整 - 查结果时,
PLSQL_PROFILER_DATA.total_ttime是纳秒单位,除以 1000000 才是毫秒 - 注意
unit_name和line#联合看——同一行可能对应多个unit_number,得对齐PLSQL_PROFILER_UNITS
关键查询:
SELECT b.line#, b.total_occur, ROUND(b.total_ttime/1000000, 2) AS ms FROM plsql_profiler_units a, plsql_profiler_data b WHERE a.runid = b.runid AND a.unit_number = b.unit_number AND a.runid = (SELECT MAX(runid) FROM plsql_profiler_runs WHERE run_comment LIKE 'my_test%') ORDER BY ms DESC FETCH FIRST 5 ROWS ONLY;
会话级实时捕获:用 gv$ob_sql_audit(仅限 OceanBase 兼容模式)
如果你连的是 Oracle 兼容模式的 OceanBase 实例(不是原生 Oracle),gv$ob_sql_audit 是更轻量的替代方案,它按会话聚合 SQL 执行指标,不需要提前开启 profiler。
- 先查当前会话 ID:
SELECT sys_context('userenv','sid') FROM dual; - 执行完目标逻辑后,立刻查该
sid的审计记录,sum(elapsed_time)可反映单条 SQL 总耗时 - 注意字段
query_sql可能被截断,长 SQL 得结合sql_id去查V$SQL补全 - 原生 Oracle 数据库没有这个视图,误用会报
ORA-00942: table or view does not exist
为什么 EXPLAIN PLAN 不能代替耗时捕获
EXPLAIN PLAN FOR ... 只给出优化器预估的执行计划和成本,不反映真实 I/O、锁等待、缓存命中率等 runtime 行为。一条预估 10ms 的 SQL,在高并发下可能因争用 latch 卡住 2 秒。
- 真实慢,得看
elapsed_time(总耗时)、cpu_time(CPU 占用)、buffer_gets(逻辑读)三者关系 - 若
elapsed_time远大于cpu_time,说明卡在 I/O 或锁上,不是执行计划问题 -
DBMS_PROFILER捕获的是实际耗时,EXPLAIN是“纸上谈兵”,两者必须配合看
真正难的不是找到慢 SQL,而是区分它是「计划差」还是「环境卡」——前者调索引和写法,后者得看系统负载、AWR 报告、甚至 OS 层磁盘队列。











