DBAtlas · 数据库运维图谱

查找过去某段时间内按耗时/CPU 排序的 Top SQL(AWR + V$SQLAREA)

Oracle性能

命令

-- AWR: top 20 by elapsed time within a snapshot range (per plan)
SELECT *
FROM  (SELECT st.sql_id,
              st.plan_hash_value,
              SUM(st.executions_delta)                       AS execs,
              ROUND(SUM(st.elapsed_time_delta)/1e6, 1)       AS elapsed_s,
              ROUND(SUM(st.cpu_time_delta)/1e6, 1)           AS cpu_s,
              ROUND(SUM(st.iowait_delta)/1e6, 1)             AS io_wait_s,
              SUM(st.buffer_gets_delta)                      AS buffer_gets,
              ROUND(SUM(st.elapsed_time_delta)/1e3
                    / NULLIF(SUM(st.executions_delta),0), 2) AS ms_per_exec,
              MAX(st.parsing_schema_name)                    AS parsing_schema
       FROM   dba_hist_sqlstat st
       WHERE  st.dbid = (SELECT dbid FROM v$database)
         AND  st.snap_id BETWEEN <begin_snap> AND <end_snap>
       GROUP  BY st.sql_id, st.plan_hash_value
       ORDER  BY elapsed_s DESC)
WHERE ROWNUM <= 20;
-- For CPU ranking: ORDER BY cpu_s DESC
-- SQL text: SELECT DBMS_LOB.SUBSTR(sql_text, 4000, 1) FROM dba_hist_sqltext WHERE sql_id = '<sql_id>';
-- Plan history of a single SQL: @?/rdbms/admin/awrsqrpt.sql

-- Current (since instance startup, still in cache) by CPU:
SELECT sql_id,
       ROUND(cpu_time/1e6,1)     AS cpu_s,
       ROUND(elapsed_time/1e6,1) AS elapsed_s,
       executions, buffer_gets, disk_reads,
       ROUND(cpu_time/1e3/NULLIF(executions,0),2) AS cpu_ms_per_exec,
       parsing_schema_name,
       SUBSTR(sql_text,1,80) AS sql_text
FROM   v$sqlarea
WHERE  parsing_schema_name NOT IN ('SYS','SYSTEM')
ORDER  BY cpu_time DESC
FETCH FIRST 20 ROWS ONLY;

作用

汇总 DBA_HIST_SQLSTAT 中的 *_DELTA 列,列出某快照范围内开销最大的 SQL,并按 plan_hash_value 细分,从而也能发现同一 SQL 的计划变化。V$SQLAREA 查询给出仍在缓存中的 SQL 的累计值。

适用场景

用于回答"昨晚 02:00 到 04:00 之间是什么压垮了系统?"、检测计划变化(相同 sql_id,不同 plan_hash_value),以及建立调优候选清单。

注意

查询 DBA_HIST_* 需要 Diagnostics Pack 许可;V$SQLAREA 不需要。AWR 只保留 Top SQL(默认 top-N),因此小而极其频繁的语句可能缺失。游标老化淘汰后 V$SQLAREA 的值会丢失。差值在重启后仍然正确,但基于缓存的查询会从零开始。

在 DBAtlas 中打开 →

相关内容