在 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_ROLE 或 DBA |
| 开启 SQL Trace | ALTER SESSION(普通用户可开自己的),全局跟踪需 DBA |
✅ 总结:如何选择?
| 场景 | 推荐方法 |
|---|---|
| 实时查看谁在跑慢 SQL | V$SESSION + V$SQL(查 last_call_et) |
| 分析最近哪些 SQL 最耗时 | V$SQL 按 elapsed_time 排序 |
| 长期性能趋势分析 | AWR 报告 |
| 深度诊断单条 SQL | 10046 trace + tkprof |
| 监控大事务/导入导出进度 | V$SESSION_LONGOPS |