Oracle中如何监控SQL执行时间?

在 Oracle 数据库中,监控 SQL 语句的执行时间是性能调优和问题排查的关键环节。Oracle 提供了多种机制来捕获和分析 SQL 的执行耗时,以下是 常用且实用的方法,按使用场景分类说明:


✅ 一、实时监控:查看当前正在执行的 SQL 及其已运行时间

方法:查询 V$SESSION + V$SQL

sql 复制代码
SELECT 
    s.sid,
    s.serial#,
    s.username,
    s.status,
    s.machine,
    s.program,
    q.sql_text,
    s.last_call_et AS "Seconds_Running",  -- 当前操作已运行秒数
    q.elapsed_time / 1000000 AS "Elapsed_Sec_Total",  -- 该SQL总耗时(秒)
    q.cpu_time / 1000000 AS "CPU_Sec"
FROM 
    v$session s
JOIN 
    v$sql q ON s.sql_id = q.sql_id
WHERE 
    s.status = 'ACTIVE'
    AND s.username IS NOT NULL
    AND s.type != 'BACKGROUND';

🔍 说明:

  • last_call_et:当前调用已持续的秒数(单位:秒),对活跃会话非常有用
  • elapsed_time:该 SQL 自首次执行以来累计总耗时(微秒),除以 1e6 转为秒。
  • 此方法适用于实时抓取慢查询

✅ 二、历史监控:查看已执行 SQL 的性能统计(AWR / V$SQL)

Oracle 会自动在共享池中缓存 SQL 的执行统计信息(通过 V$SQL 视图)。

查询最近执行过的 SQL 及其平均/总耗时:

sql 复制代码
SELECT 
    sql_id,
    substr(sql_text, 1, 100) AS sql_preview,
    executions AS execs,
    ROUND(elapsed_time / 1000000, 2) AS total_sec,
    ROUND(elapsed_time / NULLIF(executions, 0) / 1000000, 4) AS avg_sec,
    ROUND(cpu_time / NULLIF(executions, 0) / 1000000, 4) AS avg_cpu_sec,
    last_active_time
FROM 
    v$sql
WHERE 
    executions > 0
    AND last_active_time > SYSDATE - 1  -- 过去24小时
ORDER BY 
    elapsed_time DESC;

⚠️ 注意:

  • V$SQL 中的数据是内存中的缓存,实例重启或 SQL 被老化(aged out)后会丢失。
  • 适合查看近期高频或高耗时 SQL

✅ 三、长期监控:使用 AWR(Automatic Workload Repository)

AWR 是 Oracle 企业版(Enterprise Edition)提供的自动性能数据仓库,默认每小时快照一次,保留 8 天。

查看某段时间内最耗时的 SQL(Top SQL by Elapsed Time):

sql 复制代码
-- 需要知道快照 ID(snap_id)
SELECT * FROM TABLE(
    DBMS_WORKLOAD_REPOSITORY.select_sql(
        begin_snap => 12345,
        end_snap   => 12346,
        sql_id     => NULL  -- NULL 表示返回 Top SQL
    )
);

或者使用标准 AWR 报告:

sql 复制代码
-- 生成 HTML 或文本格式的 AWR 报告(需 DBA 权限)
@$ORACLE_HOME/rdbms/admin/awrrpt.sql

✅ AWR 优势:

  • 持久化存储,不受内存老化影响;
  • 包含等待事件、I/O、CPU 等完整上下文;
  • 支持跨时间段对比。
    ❌ 缺点:仅限 Enterprise Edition,且需额外许可(Diagnostics Pack)。

✅ 四、会话级跟踪:启用 SQL Trace(10046 Event)

如果要精确分析某条 SQL 的执行细节(包括各阶段耗时、等待事件),可开启 SQL Trace。

步骤:

1. 开启当前会话跟踪:
sql 复制代码
ALTER SESSION SET sql_trace = TRUE;
-- 或更详细的 10046 trace(level 12 包含绑定变量和等待事件)
ALTER SESSION SET EVENTS '10046 trace name context forever, level 12';
2. 执行你的 SQL
sql 复制代码
SELECT * FROM large_table WHERE ...;
3. 关闭跟踪
sql 复制代码
ALTER SESSION SET sql_trace = FALSE;
-- 或
ALTER SESSION SET EVENTS '10046 trace name context off';
4. 找到 trace 文件位置
sql 复制代码
SELECT value FROM v$diag_info WHERE name = 'Default Trace File';
5. 使用 tkprof 格式化分析
bash 复制代码
tkprof tracefile.trc output.txt explain=user/pass sort=exeela

📊 输出包含:

  • Parse / Execute / Fetch 各阶段耗时
  • CPU time、Elapsed time、Disk reads
  • 执行计划
    💡 适用场景:深度性能诊断,但不适用于生产环境大规模开启

✅ 五、使用 DBMS_MONITOR 跟踪特定会话或客户端

可针对某个用户、服务名或会话开启跟踪:

sql 复制代码
-- 跟踪某个客户端程序(如 JDBC 应用)
BEGIN
  DBMS_MONITOR.client_id_trace_enable(
    client_id => 'MY_APP_USER',
    waits     => TRUE,
    binds     => TRUE
  );
END;
/

后续用 tkprof 分析生成的 trace 文件。


✅ 六、监控长时间运行的操作(Long Operations)

对于 DML、DDL、备份等长时间操作,可用:

sql 复制代码
SELECT 
    opname,
    target,
    sofar,
    totalwork,
    ROUND(sofar/totalwork*100, 2) AS pct_done,
    time_remaining,
    elapsed_seconds
FROM 
    v$session_longops
WHERE 
    totalwork > 0 
    AND sofar != totalwork;

🔒 权限说明

操作 所需权限
查询 V$SESSION, V$SQL SELECT ANY DICTIONARY 或 DBA 授予 V_$SESSION
生成 AWR 报告 SELECT_CATALOG_ROLEDBA
开启 SQL Trace ALTER SESSION(普通用户可开自己的),全局跟踪需 DBA

✅ 总结:如何选择?

场景 推荐方法
实时查看谁在跑慢 SQL V$SESSION + V$SQL(查 last_call_et
分析最近哪些 SQL 最耗时 V$SQLelapsed_time 排序
长期性能趋势分析 AWR 报告
深度诊断单条 SQL 10046 trace + tkprof
监控大事务/导入导出进度 V$SESSION_LONGOPS

相关推荐
r i c k19 分钟前
数据库系统学习笔记
数据库·笔记·学习
野犬寒鸦34 分钟前
从零起步学习JVM || 第一章:类加载器与双亲委派机制模型详解
java·jvm·数据库·后端·学习
IvorySQL1 小时前
PostgreSQL 分区表的 ALTER TABLE 语句执行机制解析
数据库·postgresql·开源
·云扬·2 小时前
MySQL 8.0 Redo Log 归档与禁用实战指南
android·数据库·mysql
野生技术架构师2 小时前
SQL语句性能优化分析及解决方案
android·sql·性能优化
IT邦德2 小时前
Oracle 26ai DataGuard 搭建(RAC到单机)
数据库·oracle
惊讶的猫2 小时前
redis分片集群
数据库·redis·缓存·分片集群·海量数据存储·高并发写
不爱缺氧i2 小时前
完全卸载MariaDB
数据库·mariadb
纤纡.2 小时前
Linux中SQL 从基础到进阶:五大分类详解与表结构操作(ALTER/DROP)全攻略
linux·数据库·sql