set linesize 300 pagesize 0
SET DEF ^ TERM OFF ECHO ON AUTOP OFF VER OFF SERVEROUT ON SIZE 1000000;
SET TERM ON ECHO OFF;
set trims on
PRO
PRO generate top sql monitor html files
PRO
DEF sql_monitor_reports = '5';
set term off
SPO _sqlmon.sql;
DECLARE
l_count NUMBER := 0;
TYPE mon_rt IS RECORD (
sql_id varchar2(30),
elapsed_time number,
sql_exec_start DATE,
sql_exec_id NUMBER,
sql_plan_hash_value NUMBER,
status varchar2(10),
username varchar2(30),
avg_time number,
con_cnt number );
mon_rec mon_rt;
mon_cv SYS_REFCURSOR;
BEGIN
DBMS_OUTPUT.PUT_LINE('VAR mon_exec_start VARCHAR2(14);');
DBMS_OUTPUT.PUT_LINE('VAR mon_elapsed_time NUMBER;');
DBMS_OUTPUT.PUT_LINE('VAR mon_exec_id NUMBER;');
DBMS_OUTPUT.PUT_LINE('VAR mon_sql_plan_hash_value NUMBER;');
DBMS_OUTPUT.PUT_LINE('VAR mon_status varchar2(10);');
DBMS_OUTPUT.PUT_LINE('VAR mon_username varchar2(30);');
DBMS_OUTPUT.PUT_LINE('VAR mon_con_cnt number;');
DBMS_OUTPUT.PUT_LINE('VAR mon_report CLOB;');
DBMS_OUTPUT.PUT_LINE('VAR mon_sql_id VARCHAR2(13);');
DBMS_OUTPUT.PUT_LINE('SET ECHO OFF FEED OFF VER OFF SHOW OFF HEA OFF LIN 3000 NEWP NONE PAGES 0 LONG 2000000 LONGC 2000 SQLC MIX TAB ON TRIMS ON TI OFF TIMI OFF ARRAY 100 NUMF "" SQLP SQL> SUF sql BLO . RECSEP OFF APPI OFF AUTOT OFF;');
-- cursor variable to avoid error on 10g since v\$sql_monitor didn't exist then
OPEN mon_cv FOR
select * from
( select sql_id,elapsed_time,sql_exec_start,sql_exec_id, sql_plan_hash_value,status,username,round(avg_elap/1e6) as avg_time,con_cnt
from
( SELECT sql_id, elapsed_time, sql_exec_start, sql_exec_id, sql_plan_hash_value,
row_number() over (partition by sql_id order by elapsed_time desc) as rn,
sum(elapsed_time) over (partition by sql_id) as total_elap,
avg(elapsed_time) over (partition by sql_id) as avg_elap,
count(*) over (partition by sql_id ) as con_cnt,
username,
decode(status,'EXECUTING','EXEC','DONE (ERROR)','ERROR','DONE') as status
FROM gv$sql_monitor WHERE process_name = 'ora' and sql_plan_hash_value>0
) where rn=1 ORDER BY total_elap desc
) where rownum<=^^sql_monitor_reports.;
LOOP
FETCH mon_cv INTO mon_rec;
EXIT WHEN mon_cv%NOTFOUND;
--l_count := l_count + 1;
--IF l_count > ^^sql_monitor_reports. THEN
-- EXIT; -- exits loop
--END IF;
DBMS_OUTPUT.PUT_LINE('EXEC :mon_sql_id := '''||mon_rec.sql_id||''';');
DBMS_OUTPUT.PUT_LINE('EXEC :mon_elapsed_time := '||lpad(round(mon_rec.elapsed_time/1e6),5,'0')||';');
DBMS_OUTPUT.PUT_LINE('EXEC :mon_exec_start := '''||TO_CHAR(mon_rec.sql_exec_start, 'YYYYMMDDHH24MISS')||''';');
DBMS_OUTPUT.PUT_LINE('EXEC :mon_exec_id := '||TO_CHAR(mon_rec.sql_exec_id)||';');
DBMS_OUTPUT.PUT_LINE('EXEC :mon_sql_plan_hash_value := '||TO_CHAR(mon_rec.sql_plan_hash_value)||';');
DBMS_OUTPUT.PUT_LINE('EXEC :mon_status := '''||substr(mon_rec.status,1,4)||''';');
DBMS_OUTPUT.PUT_LINE('SPO ora_sqlmon_'||lpad(round(mon_rec.elapsed_time/1e6),5,'0')||'_'||TO_CHAR(mon_rec.sql_plan_hash_value)||'_'||mon_rec.sql_id||'_'||TO_CHAR(mon_rec.sql_exec_start, 'YYYYMMDDHH24MISS')||'_'||mon_rec.status||'_'||mon_rec.username||'_'||to_char(mon_rec.avg_time)||'_'||to_char(mon_rec.con_cnt)||'.html;');
DBMS_OUTPUT.PUT_LINE('SELECT ''<!-- ''||TO_CHAR(SYSDATE, ''YYYY-MM-DD/HH24:MI:SS'')||'' -->'' FROM dual;');
DBMS_OUTPUT.PUT_LINE('set term on');
DBMS_OUTPUT.PUT_LINE('PRO <!-- begin DBMS_SQLTUNE.REPORT_SQL_MONITOR: '||mon_rec.sql_id);
DBMS_OUTPUT.PUT_LINE('set term off');
DBMS_OUTPUT.PUT_LINE('BEGIN');
DBMS_OUTPUT.PUT_LINE(' :mon_report := DBMS_SQLTUNE.REPORT_SQL_MONITOR (');
DBMS_OUTPUT.PUT_LINE(' sql_id => :mon_sql_id,');
DBMS_OUTPUT.PUT_LINE(' sql_exec_start => TO_DATE(:mon_exec_start, ''YYYYMMDDHH24MISS''),');
DBMS_OUTPUT.PUT_LINE(' sql_exec_id => :mon_exec_id,');
DBMS_OUTPUT.PUT_LINE(' report_level => ''ALL'',');
DBMS_OUTPUT.PUT_LINE(' type => ''ACTIVE'' );');
DBMS_OUTPUT.PUT_LINE('END;');
DBMS_OUTPUT.PUT_LINE('/');
DBMS_OUTPUT.PUT_LINE('set term on');
DBMS_OUTPUT.PUT_LINE('PRO end -->');
DBMS_OUTPUT.PUT_LINE('set term off');
DBMS_OUTPUT.PUT_LINE('SELECT ''<!-- ''||TO_CHAR(SYSDATE, ''YYYY-MM-DD/HH24:MI:SS'')||'' -->'' FROM dual;');
DBMS_OUTPUT.PUT_LINE('SELECT :mon_report FROM DUAL;');
DBMS_OUTPUT.PUT_LINE('SELECT ''<!-- ''||TO_CHAR(SYSDATE, ''YYYY-MM-DD/HH24:MI:SS'')||'' -->'' FROM dual;');
DBMS_OUTPUT.PUT_LINE('SPO OFF;');
END LOOP;
CLOSE mon_cv;
END;
/
SPO OFF;
@_sqlmon.sql
这是一段 SQL*Plus 脚本,不是直接业务 SQL;属于 Oracle DBA 性能诊断工具脚本。
核心作用:批量抓取当前数据库中耗时最高的 SQL 监控信息,自动生成【Active HTML 格式的 SQL Monitor 报告】。
DBMS_SQLTUNE.REPORT_SQL_MONITOR是 Oracle 真实执行监控报告,比 AWR、explain plan 更真实,包含运行时统计:行源耗时、IO、CPU、等待事件、并行、绑定变量等。 数据源:gv$sql_monitor,该视图记录 被 SQL Monitor 监控过的 SQL 执行记录(Oracle 11g + 特性)。
工作模式:二阶生成脚本
gv$sql_monitor,动态生成中间脚本文件
_sqlmon.sql@_sqlmon.sql 执行生成出来的脚本,输出一个个
.html 报告文件,打开浏览器可直接查看可视化 SQL Monitor。set linesize 300 pagesize 0 SET DEF ^ TERM OFF ECHO ON AUTOP OFF VER OFF SERVEROUT ON SIZE 1000000; SET TERM ON ECHO OFF; set trims on
linesize 300:输出行宽;
pagesize 0:关闭分页页眉页脚
SET DEF ^:
修改替代变量符号,默认是
&改成
^,避免脚本内部
&触发变量交互,防止生成脚本出错。
TERM OFF:关闭屏幕输出(屏幕不刷大量日志,只写文件);
TERM ON打开屏幕输出
ECHO ON/OFF:是否回显执行的 SQL 文本
AUTOP OFF:关闭 autotrace;
VER OFF关闭变量替换回显
SERVEROUT ON SIZE 1000000:打开 dbms_output,缓冲区开大,PL/SQL 块可以输出大量文本,用来生成脚本内容。
TRIMS ON:去掉行尾空格。
DEF sql_monitor_reports = '5';
定义替代变量:控制 最多生成多少条 top SQL 的监控报告,默认 5 条,可以调用时传入:
def sql_monitor_reports=10;导出 10 个报告。
set term off SPO _sqlmon.sql;
SPOOL 开始写文件
_sqlmon.sql;后面 PL/SQL 里面所有DBMS_OUTPUT.PUT_LINE()输出的文本全部写入这个文件。 这是采用编程思想:PL/SQL 查询数据,动态拼接 SQL*Plus 脚本代码,写入文件,后续再执行这个文件。
DECLARE
l_count NUMBER := 0;
TYPE mon_rt IS RECORD (
sql_id varchar2(30),
elapsed_time number,
sql_exec_start DATE,
sql_exec_id NUMBER,
sql_plan_hash_value NUMBER,
status varchar2(10),
username varchar2(30),
avg_time number,
con_cnt number );
mon_rec mon_rt;
mon_cv SYS_REFCURSOR;
BEGIN
-- 定义SQL*Plus绑定变量,后续生成脚本中使用
DBMS_OUTPUT.PUT_LINE('VAR mon_exec_start VARCHAR2(14);');
DBMS_OUTPUT.PUT_LINE('VAR mon_elapsed_time NUMBER;');
DBMS_OUTPUT.PUT_LINE('VAR mon_exec_id NUMBER;');
DBMS_OUTPUT.PUT_LINE('VAR mon_sql_plan_hash_value NUMBER;');
DBMS_OUTPUT.PUT_LINE('VAR mon_status varchar2(10);');
DBMS_OUTPUT.PUT_LINE('VAR mon_username varchar2(30);');
DBMS_OUTPUT.PUT_LINE('VAR mon_con_cnt number;');
DBMS_OUTPUT.PUT_LINE('VAR mon_report CLOB;');
DBMS_OUTPUT.PUT_LINE('VAR mon_sql_id VARCHAR2(13);');
VAR xxx是 SQL*Plus 绑定变量,mon_report CLOB用来接收DBMS_SQLTUNE.REPORT_SQL_MONITOR返回的大 HTML 文本。
OPEN mon_cv FOR select * from ( select sql_id,elapsed_time,sql_exec_start,sql_exec_id, sql_plan_hash_value,status,username,round(avg_elap/1e6) as avg_time,con_cnt from ( SELECT sql_id, elapsed_time, sql_exec_start, sql_exec_id, sql_plan_hash_value, row_number() over (partition by sql_id order by elapsed_time desc) as rn, sum(elapsed_time) over (partition by sql_id) as total_elap, avg(elapsed_time) over (partition by sql_id) as avg_elap, count(*) over (partition by sql_id ) as con_cnt, username, decode(status,'EXECUTING','EXEC','DONE (ERROR)','ERROR','DONE') as status FROM gv$sql_monitor WHERE process_name = 'ora' and sql_plan_hash_value>0 ) where rn=1 ORDER BY total_elap desc ) where rownum<=^^sql_monitor_reports.;
查询逻辑拆解数据源:
gv$sql_monitor RAC 环境使用全局视图,单实例也可以运行。
过滤条件:
process_name='ora':只看数据库后台进程执行 SQL,排除并行从属之外部分后台;sql_plan_hash_value>0:过滤没有执行计划的记录。窗口函数逻辑:
partition by sql_id:按 sql_id 分组
row_number() over(partition by sql_id order by elapsed_time desc) rn=1:
同一个 sql_id 取耗时最大的那一次执行记录,避免同一个 SQL 输出多份报告。
sum(elapsed_time) over(partition by sql_id) total_elap:该 sql_id 累计总耗时(单位微秒)
avg(elapsed_time) over():单次执行平均耗时;
count(*) over():该 sql_id 一共被监控执行多少次。
外层按
total_elap desc 排序,取前 N(sql_monitor_reports)条。
elapsed_time 单位: 微秒 μs,除以 1e6 得到秒。
LOOP
FETCH mon_cv INTO mon_rec;
EXIT WHEN mon_cv%NOTFOUND;
-- 输出大量 EXEC :xxx := 值;给SQL*Plus绑定变量赋值
DBMS_OUTPUT.PUT_LINE('EXEC :mon_sql_id := '''||mon_rec.sql_id||''';');
......
-- SPOOL 文件名:把关键信息编码进文件名,方便事后识别
DBMS_OUTPUT.PUT_LINE('SPOOL ora_sqlmon_'||lpad(round(mon_rec.elapsed_time/1e6),5,'0')||'_'||TO_CHAR(mon_rec.sql_plan_hash_value)||'_'||mon_rec.sql_id||'_'||TO_CHAR(mon_rec.sql_exec_start, 'YYYYMMDDHH24MISS')||'_'||mon_rec.status||'_'||mon_rec.username||'_'||to_char(mon_rec.avg_time)||'_'||to_char(mon_rec.con_cnt)||'.html;');
生成的文件名示例:
ora_sqlmon_00243_234234234_8kdfjdfj234_20260831102000_EXEC_SYS_120_3.html
文件名包含:单次执行耗时 (秒)、plan_hash_value、sql_id、执行开始时间、状态、用户名、平均耗时、执行次数。不用打开 html,文件名就能掌握基本信息。
-- 调用 REPORT_SQL_MONITOR
DBMS_OUTPUT.PUT_LINE(' :mon_report := DBMS_SQLTUNE.REPORT_SQL_MONITOR (');
DBMS_OUTPUT.PUT_LINE(' sql_id => :mon_sql_id,');
DBMS_OUTPUT.PUT_LINE(' sql_exec_start => TO_DATE(:mon_exec_start, ''YYYYMMDDHH24MISS''),');
DBMS_OUTPUT.PUT_LINE(' sql_exec_id => :mon_exec_id,');
DBMS_OUTPUT.PUT_LINE(' report_level => ''ALL'',');
DBMS_OUTPUT.PUT_LINE(' type => ''ACTIVE'' );');
type=>'ACTIVE':生成
交互式动态 HTML,可以点开折叠执行计划,查看等待事件,不是静态文本。
report_level=>'ALL':输出全部细节:计划、统计、绑定变量、等待事件、并行信息。
sql_exec_start + sql_exec_id两个字段组合,才能唯一确定某一次 SQL 执行;只传 sql_id 会返回汇总报告。
DBMS_OUTPUT.PUT_LINE('SELECT :mon_report FROM DUAL;'); --输出CLOB html内容到spool文件
DBMS_OUTPUT.PUT_LINE('SPOOL OFF;');
SELECT :mon_report FROM DUAL;将 CLOB 报告内容输出,spool 写入 html 文件。
循环结束关闭游标;PL/SQL 块结束;
SPOOL OFF; 关闭输出文件
_sqlmon.sql。
@_sqlmon.sql
执行刚刚动态生成的脚本文件,真正完成每一条 SQL Monitor html 落地。
故障现场快速采集:数据库出现性能抖动、慢 SQL、高 CPU、高 IO,一键导出 Top-N 真实 SQL Monitor 报告。
事后分析:把 html 下载本地浏览器打开,不需要登录数据库,团队 DBA 可以共享分析。
对比:同一个 sql_id 不同 plan_hash_value 的执行报告,看执行计划变化带来性能差异。
问题 SQL:正在运行 (EXECUTING)、执行报错 (ERROR)、执行完成 (DONE) 都可以抓取。
Oracle 11gR2 /12c /18c /19c /21c;RAC 环境同样支持(使用 gv$sql_monitor)
性能应急排查:业务卡顿,来不及一个个手动调用
DBMS_SQLTUNE.REPORT_SQL_MONITOR,批量导出。
灾难演练、压力测试:压测结束运行脚本收集所有 top 监控报告留存。
巡检脚本集成,定期抓取 top SQL Monitor 归档。
v$sql_monitor:/*+ MONITOR */ hint;短快 SQL 不会出现在
gv$sql_monitor,脚本抓不到。
2.gv$sql_monitor
内存视图,实例重启清空;信息不会持久化,AWR 不保存 SQL Monitor 完整报告。故障过后再运行脚本,历史记录已经消失。
必须故障现场执行。
3.权限要求:执行脚本用户需要
grant select_catalog_role to xxx; grant execute on dbms_sqltune to xxx;
缺少
dbms_sqltune执行权限脚本报错。
4. 脚本运行目录:spool 输出文件生成在
SQL*Plus 当前工作目录;linux sqlplus 登录时所在操作系统目录。
5. 变量
^^sql_monitor_reports.,使用自定义替代符号
^,不要修改 set def 值。
6. 10g 没有
v$sql_monitor视图,脚本不支持,脚本内使用 ref cursor 做了兼容避免直接编译报错,但 10g 运行无数据。
手动单条获取 SQL Monitor:
SET LONG 1000000 SELECT DBMS_SQLTUNE.REPORT_SQL_MONITOR(sql_id=>'xxxx',sql_exec_start=>xxx,sql_exec_id=>xxx,type=>'ACTIVE',report_level=>'ALL') FROM dual;
手动要填一堆参数,一条条 spool;脚本自动筛选 top 耗时、自动拼接文件名,批量导出。
-- sqlplus / as sysdba @脚本名.sql -- 修改导出报告数量,在脚本运行前定义 DEF sql_monitor_reports = '10'; @sqlmon_collect.sql
运行完成当前目录生成一批
ora_sqlmon_*.html。
DBMS_SQLTUNE执行权限、视图访问权限_sqlmon.sqlgv$sql_monitorsql_exec_start is null脏数据过滤适用版本:Oracle 11gR2 ~ 19c/21c; 必须故障现场执行,
gv$sql_monitor是内存视图,重启实例丢失。 保存文件:gen_sqlmon_html.sql
REM ==============================================================
REM gen_sqlmon_html.sql
REM 生产加固版批量导出 SQL Monitor ACTIVE HTML报告
REM 输入参数: DEF sql_monitor_reports = 8; -- 需要导出top N
REM 执行: sqlplus / as sysdba @gen_sqlmon_html.sql
REM 输出: sqlmon_*.html, 临时文件 _sqlmon.sql (脚本自动删除)
REM ==============================================================
SET DEF ^ TERM OFF ECHO OFF AUTOP OFF VER OFF SERVEROUT ON SIZE 2000000;
SET TERM ON;
SET LINESIZE 300 PAGESIZE 0 TRIMS ON FEEDBACK OFF;
PRO
PRO ########################################################
PRO ## Oracle SQL‑Monitor HTML批量采集工具(生产加固版)
PRO ########################################################
PRO
REM 定义导出报告数量,可外部传入,默认8
DEF sql_monitor_reports = '8';
REM 权限校验
DECLARE
v_cnt NUMBER;
BEGIN
SELECT COUNT(*) INTO v_cnt FROM all_objects WHERE object_name='DBMS_SQLTUNE' AND owner='SYS';
IF v_cnt=0 THEN
DBMS_OUTPUT.PUT_LINE('!!! ERROR: DBMS_SQLTUNE 对象不存在,版本不支持!');
END IF;
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('!!! ERROR 权限异常:'||SQLERRM);
END;
/
REM 开始生成中间脚本
SET TERM OFF;
SPOOL _sqlmon.sql;
DECLARE
l_count NUMBER :=0;
l_max_reports NUMBER := TO_NUMBER('^^sql_monitor_reports.');
TYPE mon_rt IS RECORD (
sql_id VARCHAR2(30),
elapsed_time NUMBER,
sql_exec_start DATE,
sql_exec_id NUMBER,
sql_plan_hash_value NUMBER,
status VARCHAR2(10),
username VARCHAR2(30),
avg_time NUMBER,
con_cnt NUMBER
);
mon_rec mon_rt;
mon_cv SYS_REFCURSOR;
BEGIN
-- 定义SQL*Plus绑定变量
DBMS_OUTPUT.PUT_LINE('VAR mon_exec_start VARCHAR2(14);');
DBMS_OUTPUT.PUT_LINE('VAR mon_elapsed_time NUMBER;');
DBMS_OUTPUT.PUT_LINE('VAR mon_exec_id NUMBER;');
DBMS_OUTPUT.PUT_LINE('VAR mon_sql_plan_hash_value NUMBER;');
DBMS_OUTPUT.PUT_LINE('VAR mon_status VARCHAR2(10);');
DBMS_OUTPUT.PUT_LINE('VAR mon_username VARCHAR2(30);');
DBMS_OUTPUT.PUT_LINE('VAR mon_con_cnt NUMBER;');
DBMS_OUTPUT.PUT_LINE('VAR mon_report CLOB;');
DBMS_OUTPUT.PUT_LINE('VAR mon_sql_id VARCHAR2(13);');
DBMS_OUTPUT.PUT_LINE('SET ECHO OFF FEED OFF VER OFF SHOW OFF HEA OFF LIN 3000 NEWP NONE PAGES 0 ');
DBMS_OUTPUT.PUT_LINE('LONG 2000000 LONGC 2000 SQLC MIX TAB ON TRIMS ON TI OFF TIMI OFF ARRAY 100 ');
DBMS_OUTPUT.PUT_LINE('NUMF "" SQLP SQL> SUF sql BLO . RECSEP OFF APPI OFF AUTOT OFF;');
OPEN mon_cv FOR
SELECT * FROM (
SELECT
sql_id,
elapsed_time,
sql_exec_start,
sql_exec_id,
sql_plan_hash_value,
status,
username,
ROUND(avg_elap/1e6) avg_time,
con_cnt
FROM (
SELECT
sql_id,
elapsed_time,
sql_exec_start,
sql_exec_id,
sql_plan_hash_value,
ROW_NUMBER() OVER(PARTITION BY sql_id ORDER BY elapsed_time DESC) rn,
SUM(elapsed_time) OVER(PARTITION BY sql_id) total_elap,
AVG(elapsed_time) OVER(PARTITION BY sql_id) avg_elap,
COUNT(*) OVER(PARTITION BY sql_id) con_cnt,
username,
DECODE(status,'EXECUTING','EXEC','DONE (ERROR)','ERROR','DONE') status
FROM gv$sql_monitor
WHERE process_name = 'ora'
AND sql_plan_hash_value > 0
AND sql_exec_start IS NOT NULL
AND username NOT IN ('SYS','SYSTEM') -- 过滤系统用户
) WHERE rn = 1
ORDER BY total_elap DESC
) WHERE ROWNUM <= l_max_reports;
LOOP
FETCH mon_cv INTO mon_rec;
EXIT WHEN mon_cv%NOTFOUND;
l_count := l_count +1;
DBMS_OUTPUT.PUT_LINE('EXEC :mon_sql_id := '''||mon_rec.sql_id||''';');
DBMS_OUTPUT.PUT_LINE('EXEC :mon_elapsed_time := '||ROUND(mon_rec.elapsed_time/1e6)||';');
DBMS_OUTPUT.PUT_LINE('EXEC :mon_exec_start := '''||TO_CHAR(mon_rec.sql_exec_start,'YYYYMMDDHH24MISS')||''';');
DBMS_OUTPUT.PUT_LINE('EXEC :mon_exec_id := '||mon_rec.sql_exec_id||';');
DBMS_OUTPUT.PUT_LINE('EXEC :mon_sql_plan_hash_value := '||mon_rec.sql_plan_hash_value||';');
DBMS_OUTPUT.PUT_LINE('EXEC :mon_status := '''||SUBSTR(mon_rec.status,1,4)||''';');
-- 缩短文件名:时间戳_耗时_sqlid_planhash.html,规避文件名过长
DECLARE
v_filename VARCHAR2(255);
BEGIN
v_filename := 'sqlmon_'
||TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS')||'_'
||ROUND(mon_rec.elapsed_time/1e6)||'s_'
||mon_rec.sql_id||'_'
||mon_rec.sql_plan_hash_value||'.html';
DBMS_OUTPUT.PUT_LINE('SPOOL '||v_filename||';');
END;
DBMS_OUTPUT.PUT_LINE('SELECT ''<!-- GENERATED:'||TO_CHAR(SYSDATE,''YYYY‑MM‑DD HH24:MI:SS'')||' sql_id:''||:mon_sql_id||'' -->'' FROM dual;');
DBMS_OUTPUT.PUT_LINE('BEGIN');
DBMS_OUTPUT.PUT_LINE(' :mon_report := DBMS_SQLTUNE.REPORT_SQL_MONITOR(');
DBMS_OUTPUT.PUT_LINE(' sql_id => :mon_sql_id,');
DBMS_OUTPUT.PUT_LINE(' sql_exec_start => TO_DATE(:mon_exec_start, ''YYYYMMDDHH24MISS''),');
DBMS_OUTPUT.PUT_LINE(' sql_exec_id => :mon_exec_id,');
DBMS_OUTPUT.PUT_LINE(' report_level => ''ALL'',');
DBMS_OUTPUT.PUT_LINE(' type => ''ACTIVE'' );');
DBMS_OUTPUT.PUT_LINE('END;');
DBMS_OUTPUT.PUT_LINE('/');
DBMS_OUTPUT.PUT_LINE('SELECT :mon_report FROM DUAL;');
DBMS_OUTPUT.PUT_LINE('SPOOL OFF;');
END LOOP;
CLOSE mon_cv;
DBMS_OUTPUT.PUT_LINE('PRO -- Total generated sqlmon report count: '|| l_count);
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('PRO !!! PL/SQL ERROR: '||SQLERRM);
IF mon_cv%ISOPEN THEN CLOSE mon_cv; END IF;
END;
/
SPOOL OFF;
SET TERM ON;
PRO
PRO 执行动态生成脚本 _sqlmon.sql ...
PRO
@_sqlmon.sql
REM 清理临时脚本文件
HOST rm -f _sqlmon.sql;
PRO
PRO =====================================================
PRO 采集完成!
PRO 输出文件:当前操作系统目录下 sqlmon_*.html
PRO 提示:sqlplus spool文件输出路径 = sqlplus登录时OS工作目录
PRO =====================================================
SET DEF &;
生成的示例文件
gen_sqlmon_html.zip
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/12798004/viewspace-3181266/ ,如需转载,请注明出处,否则将追究法律责任。