一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

如何通过Oracle 19c的实时SQL监控工具追踪存储过程的执行进度?

时间:2026-07-11 09:56:52 编辑:袖梨 来源:一聚教程网

判断存储过程是否被SQL Monitor自动捕获,关键看其内部单条SQL是否满足:CPU+I/O时间≥5秒、启用并行或含/+ MONITOR /提示;V$SQL_MONITOR仅捕获语句级而非过程级执行。

怎么判断存储过程是否被 SQL Monitor 自动捕获

oracle 19c 的 v$sql_monitor 不会监控所有存储过程,只对满足条件的 sql 执行自动启用监控。关键判断依据是:单次执行预计或实际消耗 cpu + i/o 时间 ≥ 5 秒,或使用了并行执行(px),或显式加了 /*+ monitor */ 提示。

如果存储过程里全是短平快 DML(比如每条 UPDATE 几毫秒),哪怕总耗时几分钟,也可能根本不出现在 V$SQL_MONITOR 里——因为监控触发点在「单条语句」,不是「整个过程」。

  • 查当前活跃且被监控的会话:SELECT sql_id, status, elapsed_time, cpu_time, sql_text FROM v$sql_monitor WHERE status = 'EXECUTING';
  • 确认某条 SQL 是否带 MONITOR 提示:SELECT sql_fulltext FROM v$sql WHERE sql_id = 'xxx';,看开头是否有 /*+ MONITOR */
  • 若没命中自动条件,又必须监控,得在调用前手动加提示,例如:EXEC /*+ MONITOR */ your_procedure_name;

如何用 V$SQL_MONITOR 查看正在执行的语句位置

V$SQL_MONITOR 本身不显示“执行到第几行”,但能告诉你当前正在运行哪条 SQL、它卡在哪一步、已耗多少资源。真正反映进度的是 sql_idsql_exec_start 对应的那条语句,而不是存储过程名。

常见误区是查 sql_text LIKE '%your_proc_name%',结果为空——因为 V$SQL_MONITOR 存的是最终解析后的 SQL 文本,不是 PL/SQL 源码;过程体里的 INSERT INTO t SELECT ... 才可能被监控,而 FOR i IN 1..1000 LOOP 这种循环控制逻辑不会出现在视图里。

  • 定位当前执行语句:SELECT sql_id, sql_text, status, elapsed_time/1000000 elapsed_sec, px_servers_requested FROM v$sql_monitor WHERE session_id = SYS_CONTEXT('USERENV', 'SID') AND status = 'EXECUTING';
  • 配合 V$SQL_PLAN_MONITOR 看具体操作步进:SELECT operation, options, start_time, end_time, output_rows FROM v$sql_plan_monitor WHERE sql_id = 'xxx' AND plan_line_id > 0 ORDER BY first_refresh_time;
  • 注意 output_rows 字段:对 INSERT/SELECT 类语句,它代表已处理行数;对 UPDATE/DELETE,它代表已修改行数——这是最接近“进度”的量化指标

为什么 TKPROF 或 SQL_TRACE 不能实时看到进度

ALTER SESSION SET SQL_TRACE = TRUE; 生成的是事后分析用的 .trc 文件,内容是完整执行完才落盘的。你在过程跑着的时候打开文件,只会看到零星初始化记录,真正的 SQL 执行块、绑定变量、统计信息都得等过程结束才能写入。

更麻烦的是,.trc 文件默认路径由 user_dump_dest 决定,而 19c 默认启用了 ADRCI 和自动诊断库(ADR),跟踪文件实际存放在 $ORACLE_BASE/diag/rdbms/<db_name>/<instance_name>/trace/ 下,文件名类似 <instance_name>_ora_12345.trc,不是直观的 ora*.trc。

  • 查当前会话跟踪文件路径:SELECT value FROM v$diag_info WHERE name = 'Default Trace File';
  • 别指望边跑边 tail -f —— 即使文件在写,内容也是按块缓冲,且无结构化进度标记
  • 真要实时抓中间状态,唯一办法是让存储过程自己输出:用 DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS 在循环中更新 sofar 字段,再查 V$SESSION_LONGOPS

DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS 是唯一靠谱的进度反馈方式

Oracle 官方没提供“查看 PL/SQL 行号执行位置”的接口,V$SESSION_LONGOPS 是唯一支持主动上报进度的机制,但它要求你提前在存储过程中埋点,不是开个开关就能用。

典型用法是在大循环开头调用 SET_SESSION_LONGOPS 初始化,在每次迭代后调用 SET_SESSION_LONGOPS 更新 sofar,最后调用一次标记完成。否则查 V$SESSION_LONGOPS 就是空的。

  • 初始化示例:DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS(rindex => longops_rindex, slno => 0, opname => 'MY_PROC', target_desc => 'Processing records', sofar => 0, totalwork => 10000);
  • 循环中更新:DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS(rindex => longops_rindex, sofar => i);
  • 查进度:SELECT opname, target_desc, sofar, totalwork, round(sofar/totalwork*100,1) pct_done FROM v$session_longops WHERE sofar
  • 注意:rindex 是返回值,必须保存并在后续调用中复用;totalwork 必须是确定值,不能是动态 COUNT(*) 结果(否则无法预估)

没有预先埋点,就只能靠 V$SQL_MONITOR 看当前 SQL 耗时和输出行数,或者靠 V$SESSIONlast_call_et 粗略判断“这个会话挂了多久”,但无法知道执行到了哪一行逻辑。

热门栏目