通过SQL Monitor 实时执行监控抓取TOP N慢SQL,首先上SQL,声明一下,这个脚本来自刘永浦老师的脚本,这个脚本使用比较普遍,所以未经刘老师允许,刘老师看见,请见谅,实在是抱歉。
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 = '$topn';
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
gv$sql_monitor(全局 SQL 监控视图)+
DBMS_SQLTUNE.REPORT_SQL_MONITOR 实现。输入变量:
topn(DEF sql_monitor_reports = '$topn'),
代表抓取 TOP N 慢 SQL;
输出:一批独立 HTML 文件,每个文件对应 一条 正在执行 / 刚执行完的慢 SQL 完整执行剖析报告;
执行逻辑: 先动态生成临时 SQL 脚本 → 再自动调用临时脚本批量导出 HTML → 最后清理临时文件。
MONITOR hint;存储每条 SQL 单次执行的完整运行快照:耗时、执行起止时间、执行 ID、执行状态、操作用户、执行计划 HASH、并行度、平均耗时、并发次数等。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.
sql_plan_hash_value>0;row_number() partition by sql_id order by elapsed_time desc rn=1;
avg_time:单次执行平均耗时(秒)
con_cnt:该 SQL 一共执行多少次
status 格式化:EXECUTING = 正在运行、ERROR = 执行报错、DONE = 正常执行完成
dbms_output 逐行输出 SQLPlus 命令,写入临时文件:DBMS_SQLTUNE.REPORT_SQL_MONITOR
type=>'ACTIVE':生成交互式动态 HTML(可看执行步骤、等待事件、行扫描、IO、CPU 消耗)
report_level=>'ALL':输出全量信息(等待事件、执行计划、行统计、绑定变量、并行信息)
打印 CLOB 报告到文件,关闭 spool。
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
DEF ^
:把变量标识符修改为 ^,避免 & 变量冲突;
SERVEROUT ON SIZE 1000000
:放大缓冲区,防止长报告截断;
trims on
:去除行末尾空格,缩小 HTML 文件体积;
批量生成时关闭终端输出,提升导出速度,不刷屏。
DBMS_SQLTUNE.REPORT_SQL_MONITOR(type=>'ACTIVE') 交互式 HTML 包含:内存 / PGA 临时表空间使用情况。
SQL 完整文本、绑定变量值;
@sqlmon_script topn=20,自动产出 20 条累计耗时最高 SQL 的 HTML 报告,归档留存,用于性能复盘、慢 SQL 优化台账。案例分享:


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/12798004/viewspace-3175968/ ,如需转载,请注明出处,否则将追究法律责任。