暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

ORACLE查询正在执行的long running sql

DBA闲思杂想录 2022-11-12
2387

Oracle数据库中如何查找、定位一些正在执行但是运行时间很长的SQL语句(long running sql)呢?注意,我们这里只查看正在执行long running sql,而不是查询历史执行时间很长的SQL语句(请不要混淆)。大概有下面一些方法供参考。

1:通过V$SQL_MONITOR来查找

Oracle 11g中引入了新的动态性能视图V$SQL_MONITOR,该视图用以显示Oracle监视的SQL语句信息。SQL Monitor会对那些并行执行或者消耗5秒以上CPU时间或I/O时间的SQL语句自动监控,同时在V$SQL_MONITOR视图中产生一条记录。V$SQL_MONITOER收集的信息每秒刷新一次,接近实时,当SQL执行完毕,信息并不会立即从V$SQL_MONITOER中删除,至少会保留1分钟,V$SQL_PLAN_MONITOR视图中的执行计划信息也是每秒更新一次,当SQL执行完毕,它们同样至少被保留1分钟,并可以会存在更长的时间,取决于新的查询所需要的空间。


使用v$sql_monitor视图中所监控的SQL语句时需在满足以下条件:


    1)  自动监控任何并行语句


    2)  如果一个SQL语句消耗了超过5秒的CPU或I/O时间,则会自动监控


    3)  监控任何在语句级启用监控的SQL语句(使用/*+ monitor */提示SQL语句)


注意:要开启sql mointor这个特性/功能的前提条件:


    1:初始化参数STATISTICS_LEVEL必须设置为TYPICAL或ALL。


    2:CONTROL_MANAGEMENT_PACK_ACCESS必须设置为DIAGNOSTIC+TUNING。


使用下面SQL查询,如果你使用PL/SQL Developer等图形工具,可以去掉设置格式部分。

set termout off
set markup html on spool on -
HEAD '<title>sql monitor long running</title> -
<style type="text/css"> -
table{-
        font-family: "courier new",verdana, arial, sans-serif;-
        font-size: 12px;-
        color: #333333;-
        border-width: 1px;-
        border-color: #3A3A3A;-
        border-collapse: collapse;-
    }-
 th {-
        border-width: 1px;-
        padding: 8px;-
        border-style: solid;-
        border-color: #FFA6A6;-
        background-color: #D56A6A;-
        color: #ffffff;-
    }-
 tr:hover td {-
        cursor: pointer;-
        background-color: #F7CFCF;-
    }-
 td {-
        border-width: 1px;-
        padding: 8px;-
        border-style: solid;-
        border-color: #FFA6A6;-
        background-color: #ffffff;-
    }-
</style>'

spool sql_monitor_running_sql.html
select sid
      ,session_serial#
      ,username
      ,program
      ,to_char(sql_exec_start,'yyyy-mm-dd hh24:mi:ss') sql_exec_start
      ,sql_id
      ,sql_text
      ,is_full_sqltext
      ,elapsed_time/1000000
from v$sql_monitor
where status in ('QUEUED','EXECUTING');
spool off;
set markup html off;

复制

输入对应的SQL_ID,查看对应的报告。

SET LONG 1000000
SET LONGCHUNKSIZE 1000000
SET LINESIZE   1000
SET PAGESIZE 0
SET TRIM ON
SET TRIMSPOOL ON
SET ECHO OFF
SET FEEDBACK OFF
spool   monitor_long_running.html
SELECT DBMS_SQLTUNE.report_sql_monitor(sql_id   =>'fb19u7fh7wd7v',type=> 'HTML'AS report FROM dual;
spool off;

复制


2:通过V$SESSION_LONGOPS来查找

V$SESSION_LONGOPS 显示运行时间超过 6 秒(以绝对时间为单位)的各种操作的状态。这个视图不但可以监控运行时间比较长的SQL,也会记录RMAN备份、EXP/EXPDP、收集统计信息、排序等操作,基本数据库所有运行时间超过6秒的SQL都会记录在这个视图中.

如果要使用V$SESSION_LONGOPS的话,也必须满足下面两个条件。 


Set the TIMED_STATISTICS or SQL_TRACE parameters to true   
必须将初始化参数 timed_statistics设置为true或者开启sql_trace                                                               
                                                                                                                               
- Gather statistics for your objects with the DBMS_STATS package    
必须用ANALYZE或者DBMS_STATS包对对象收集过统计信息。 

复制

下面是具体的SQL语句:

set lines 1080 pagesize 1000;
col inst_id for 99;
col con_id for 99;
col sid for 99999;
col serial# for 99999;
col sql_text for a45 trunc
col sql_id for a14;
col remaining_time for a6 head "REMAIN_TIME"
col elapsed_time for a6 head "RUN|DURATION"
alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';
select  s.inst_id
       ,s.con_id
       ,s.sid
       ,s.serial#
       ,sql.sql_id
       ,sql.sql_text 
       ,start_time
       --,last_update_time
       ,round(op.time_remaining/60) || ':' || mod(op.time_remaining,60)   as remaining_time  
       ,round(op.elapsed_seconds/60) || ':' || mod(op.elapsed_seconds,60as elapsed_time
       ,round((sofar/totalwork) * 100,2as pct_done
from    gv$session s, 
        gv$sqlarea sql
        gv$session_longops op
where     
        s.sid=op.sid
and     s.sql_id = sql.sql_id
and     s.sid = op.sid
and     s.status  = 'ACTIVE'
and     op.totalwork > op.sofar
and     s.sid not in (select distinct sid from gv$mystat where rownum < 2)
order by 4 desc;

--通过上面SQL语句获取的SQL_ID,找到具体的SQL语句

select sql_fulltext from V$sql where sql_id='&sql_id';

复制

注意,使用V$SESSION_LONGOPS来查找long runnging sql,可能会遗漏一些SQL,因为比如某个SQL语句执行时间比较长,但是每个操作都没有超过6秒。那么这个SQL可能不会被捕获到。

方式3:通过V$SESSION和V$SQLAREA来查询。

注意,下面SQL统计的SQL运行时间为AVG_ELAPSED_TIME可能跟V$SQL_MONITOR中的时间有出入,确切来说,V$SQL_MONITOR中的才是SQL运行时长的精准时间。这个是因为统计口径问题,这里统计的是SQL运行的平均时间,而不是这个SQL的真正运行时间,所以下面SQL仅供参考。

SELECT S.USERNAME  
      ,S.SID
      ,S.SERIAL#
      ,A.SQL_ID
      ,S.OSUSER
      ,S.MACHINE
      ,S.TERMINAL
      ,S.PROGRAM
      ,S.EVENT
      ,S.SECONDS_IN_WAIT
      ,S.BLOCKING_SESSION
      ,S.STATUS
      ,S.LAST_CALL_ET  
      ,DECODE(A.EXECUTIONS, 0ROUND(A.ELAPSED_TIME/1000000,2),ROUND(A.ELAPSED_TIME/1000000/NVL(A.EXECUTIONS,1),2)) AS AVG_ELAPSED_TIME
      ,A.EXECUTIONS
      ,A.SQL_TEXT
      --,A.SQL_FULLTEXT
FROM V$SESSION S ,
     V$SQLAREA A 
WHERE  S.SQL_HASH_VALUE = A.HASH_VALUE 
  AND  S.SQL_ADDRESS = A.ADDRESS
ORDER BY AVG_ELAPSED_TIME DESC;

复制


文章转载自DBA闲思杂想录,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论