第53期 排查分析最近30天内SQL语句性能出现退化的SQL

来源:这里教程网 时间:2026-03-03 22:58:16 作者:

DBA_HIST_SQLSTAT 显示 SQL 统计信息的历史数据。

此视图基于一系列标准,从 V$SQL 获取TOP SQL 语句及其统计信息。总计值表示自实例启动以来的累计统计值。增量值表示 DBA_HIST_SNAPSHOT 视图中 BEGIN_INTERVAL_TIME 到 END_INTERVAL_TIME 时间间隔内的统计值。

此视图与 DBA_HIST_OPTIMIZER_ENV、DBA_HIST_SQLTEXT 和 DBA_HIST_SQL_PLAN 视图结合使用,以提供 SQL 统计信息的完整历史记录。 我们可以根据此试图分析最近30天内SQL语句的性能稳定性,识别出执行时间出现退化的SQL

SELECT sq.sql_id,
       sq.plan_hash_value,
       COUNT(DISTINCT sq.snap_id) as period_count,
       MIN(sn.begin_interval_time) as first_seen,
       MAX(sn.end_interval_time) as last_seen,
       ROUND(MIN(sq.elapsed_time_delta / NULLIF(sq.executions_delta, 0) /
                 1000000),
             4) as min_elapsed_sec,
       ROUND(MAX(sq.elapsed_time_delta / NULLIF(sq.executions_delta, 0) /
                 1000000),
             4) as max_elapsed_sec,
       ROUND(MAX(sq.elapsed_time_delta / NULLIF(sq.executions_delta, 0) /
                 1000000) /
             NULLIF(MIN(sq.elapsed_time_delta /
                        NULLIF(sq.executions_delta, 0) / 1000000),
                    0),
             2) as perf_variance,
       CASE
         WHEN MAX(sq.elapsed_time_delta / NULLIF(sq.executions_delta, 0) /
                  1000000) /
              NULLIF(MIN(sq.elapsed_time_delta /
                         NULLIF(sq.executions_delta, 0) / 1000000),
                     0) > 5 THEN
          '严重退化'
         WHEN MAX(sq.elapsed_time_delta / NULLIF(sq.executions_delta, 0) /
                  1000000) /
              NULLIF(MIN(sq.elapsed_time_delta /
                         NULLIF(sq.executions_delta, 0) / 1000000),
                     0) > 2 THEN
          '轻微退化'
         ELSE
          '稳定'
       END as stability
  FROM dba_hist_sqlstat sq
  JOIN dba_hist_snapshot sn
    ON sq.snap_id = sn.snap_id
 WHERE sq.executions_delta > 10
   AND sq.elapsed_time_delta > 0
   AND sn.begin_interval_time > SYSDATE - 30 -- 最近30天
 GROUP BY sq.sql_id, sq.plan_hash_value
HAVING COUNT(DISTINCT sq.snap_id) >= 3 -- 至少出现在3个时间段
 ORDER BY perf_variance DESC;

这段SQL语句的作用是从Oracle的AWR历史数据中,分析SQL语句的性能稳定性。具体来说,它通过关联dba_hist_sqlstat和dba_hist_snapshot视图,获取最近30天内出现至少3个不同时间段(快照)的SQL语句,并计算其执行时间的波动情况,从而判断SQL性能是否出现退化。

步骤解析:

    从dba_hist_sqlstat(SQL历史统计信息)和dba_hist_snapshot(快照历史)中选取数据。

  1. 关联条件为sq.snap_id = sn.snap_id。

  2. 筛选条件:

    每个快照周期内执行次数大于10(sq.executions_delta > 10),这是为了排除执行次数太少导致的偶然性。

  3. 每个快照周期内总耗时大于0(sq.elapsed_time_delta > 0)。

  4. 快照开始时间在最近30天内(sn.begin_interval_time > SYSDATE - 30)。

  5. 按照SQL_ID和计划哈希值(plan_hash_value)分组,这样同一个SQL语句如果执行计划不同(即不同plan_hash_value)会被分开统计。

  6. 分组后,只选择出现在至少3个不同快照周期中的SQL(COUNT(DISTINCT sq.snap_id) >= 3)。

  7. 计算指标:

    period_count: 该SQL出现在多少个不同的快照周期中。

  8. first_seen: 该SQL第一次出现的时间(最早快照开始时间)。

  9. last_seen: 该SQL最后一次出现的时间(最晚快照结束时间)。

  10. min_elapsed_sec: 每个快照周期内,每次执行的平均耗时(秒)的最小值。注意:elapsed_time_delta是微秒,除以1000000得到秒。

  11. max_elapsed_sec: 每个快照周期内,每次执行的平均耗时(秒)的最大值。

  12. perf_variance: 性能波动,即最大平均耗时除以最小平均耗时。如果最小平均耗时为0,则除数为NULL,结果为NULL。

  13. stability: 根据perf_variance的值判断稳定性。如果波动大于5倍,标记为“严重退化”;大于2倍,标记为“轻微退化”;否则为“稳定”。

  14. 结果按照perf_variance降序排列,这样性能退化最严重的SQL排在最前面。

总结:该SQL用于监控最近30天内,执行次数较多(每个快照周期执行超过10次)且出现在至少3个快照周期中的SQL语句,分析其平均执行时间的变化,从而找出性能不稳定的SQL(特别是性能退化的SQL)。

使用场景:

1.  性能调优

DBA可以用此查询快速发现哪些SQL出现了性能退化

  • 帮助定位需要优化的SQL语句

    查询结果的解读示例:

    假设结果中有一条记录:

    SQL_ID: "abc123"

  • min_elapsed_sec: 0.5秒

  • max_elapsed_sec: 3.0秒

  • perf_variance: 6.0

  • stability: "严重退化"

    这表示:

      该SQL在过去30天内至少出现在3个不同的监控周期

    1. 最好的时候平均执行0.5秒

    2. 最差的时候平均执行3.0秒

    3. 性能波动了6倍,属于严重退化

    4. 需要DBA重点关注和调优

    这个查询是Oracle数据库性能监控和调优中一个非常实用的工具,可以帮助DBA快速识别性能问题。

    数据类型 是否为空 说明
    SNAP_ID NUMBER NOT NULL 唯一快照 ID
    DBID NUMBER NOT NULL 快照的数据库 ID
    INSTANCE_NUMBER NUMBER NOT NULL 快照的实例编号
    SQL_ID VARCHAR2(13) NOT NULL 库缓存中父游标的 SQL 标识符
    PLAN_HASH_VALUE NUMBER NOT NULL SQL 游标执行计划的数值表示。比较 PLAN_HASH_VALUE 值可以更容易地(相比于逐行比较两个计划)识别两个计划是否相同。
    OPTIMIZER_COST NUMBER 优化器估计的查询成本
    OPTIMIZER_MODE VARCHAR2(10) SQL 语句执行时使用的优化器模式
    OPTIMIZER_ENV_HASH_VALUE NUMBER 优化器环境的哈希值
    SHARABLE_MEM NUMBER 此子游标使用的共享内存字节数
    LOADED_VERSIONS NUMBER 上下文堆是否已加载 (1 | 0)
    VERSION_COUNT NUMBER 与此游标关联的子游标数量
    MODULE VARCHAR2(64) SQL 语句解析时正在执行的(通过调用 DBMS_APPLICATION_INFO.SET_MODULE 设置的)模块名称
    ACTION VARCHAR2(64) SQL 语句解析时正在执行的(通过调用 DBMS_APPLICATION_INFO.SET_ACTION 设置的)操作名称
    SQL_PROFILE VARCHAR2(64) 应用的 SQL Profile 名称
    FORCE_MATCHING_SIGNATURE NUMBER 当 CURSOR_SHARING 参数设置为 FORCE 时使用的签名
    PARSING_SCHEMA_ID NUMBER 用于创建此子游标的模式 ID
    PARSING_SCHEMA_NAME VARCHAR2(128) 用于创建此子游标的模式名称
    PARSING_USER_ID NUMBER 用于创建此子游标的用户 ID
    FETCHES_TOTAL NUMBER SQL 语句相关的累计提取次数
    FETCHES_DELTA NUMBER SQL 语句相关的增量提取次数
    END_OF_FETCH_COUNT_TOTAL NUMBER 游标被放入库缓存后,此游标完全执行完毕的累计次数。如果游标未成功执行,或者在游标关闭或重新执行前仅提取了其生成的首批数据行(即部分执行),则此统计值不会增加。END_OF_FETCH_COUNT 列的值定义为小于或等于 EXECUTIONS 列的值。
    END_OF_FETCH_COUNT_DELTA NUMBER 游标被放入库缓存后,此游标完全执行完毕的增量次数。如果游标未成功执行,或者在游标关闭或重新执行前仅提取了其生成的首批数据行(即部分执行),则此统计值不会增加。
    SORTS_TOTAL NUMBER 针对此子游标执行的累计排序次数
    SORTS_DELTA NUMBER 针对此子游标执行的增量排序次数
    EXECUTIONS_TOTAL NUMBER 自对象被放入库缓存后,执行的累计次数
    EXECUTIONS_DELTA NUMBER 自对象被放入库缓存后,执行的增量次数
    PX_SERVERS_EXECS_TOTAL NUMBER 并行执行服务器执行的累计次数
    PX_SERVERS_EXECS_DELTA NUMBER 并行执行服务器执行的增量次数
    LOADS_TOTAL NUMBER 对象被加载或重新加载的累计次数
    LOADS_DELTA NUMBER 对象被加载或重新加载的增量次数
    INVALIDATIONS_TOTAL NUMBER 此子游标失效的累计次数
    INVALIDATIONS_DELTA NUMBER 此子游标失效的增量次数
    PARSE_CALLS_TOTAL NUMBER 对此子游标的累计解析调用次数
    PARSE_CALLS_DELTA NUMBER 对此子游标的增量解析调用次数
    DISK_READS_TOTAL NUMBER 此子游标的累计磁盘读取次数
    DISK_READS_DELTA NUMBER 此子游标的增量磁盘读取次数
    BUFFER_GETS_TOTAL NUMBER 此子游标的累计缓冲区获取次数
    BUFFER_GETS_DELTA NUMBER 此子游标的增量缓冲区获取次数
    ROWS_PROCESSED_TOTAL NUMBER 已解析 SQL 语句返回的累计行数
    ROWS_PROCESSED_DELTA NUMBER 已解析 SQL 语句返回的增量行数
    CPU_TIME_TOTAL NUMBER 此游标用于解析、执行或提取所消耗的累计 CPU 时间(微秒)
    CPU_TIME_DELTA NUMBER 此游标用于解析、执行或提取所消耗的增量 CPU 时间(微秒)
    ELAPSED_TIME_TOTAL NUMBER 此游标用于解析、执行或提取所消耗的累计经过时间(微秒)。如果游标使用并行执行,ELAPSED_TIME_TOTAL 是查询协调器的时间加上所有并行查询从进程处理时间的累计时间。
    ELAPSED_TIME_DELTA NUMBER 此游标用于解析、执行或提取所消耗的增量经过时间(微秒)
    IOWAIT_TOTAL NUMBER 累计用户 I/O 等待时间(微秒)
    IOWAIT_DELTA NUMBER 增量用户 I/O 等待时间(微秒)
    CLWAIT_TOTAL NUMBER 累计集群等待时间(微秒)
    CLWAIT_DELTA NUMBER 增量集群等待时间(微秒)
    APWAIT_TOTAL NUMBER 累计应用程序等待时间(微秒)
    APWAIT_DELTA NUMBER 增量应用程序等待时间(微秒)
    CCWAIT_TOTAL NUMBER 累计并发等待时间(微秒)
    CCWAIT_DELTA NUMBER 增量并发等待时间(微秒)
    DIRECT_WRITES_TOTAL NUMBER 直接写入的累计次数
    DIRECT_WRITES_DELTA NUMBER 直接写入的增量次数
    PLSEXEC_TIME_TOTAL NUMBER 累计 PL/SQL 执行时间(微秒)
    PLSEXEC_TIME_DELTA NUMBER 增量 PL/SQL 执行时间(微秒)
    JAVEXEC_TIME_TOTAL NUMBER 累计 Java 执行时间(微秒)
    JAVEXEC_TIME_DELTA NUMBER 增量 Java 执行时间(微秒)
    IO_OFFLOAD_ELIG_BYTES_TOTAL NUMBER 可由 Exadata 存储系统过滤的 I/O 字节的累计值。 相关信息:请参阅 Oracle Exadata Storage Server 软件手册。
    IO_OFFLOAD_ELIG_BYTES_DELTA NUMBER 可由 Exadata 存储系统过滤的 I/O 字节的增量值。 相关信息:请参阅 Oracle Exadata Storage Server 软件手册。
    IO_INTERCONNECT_BYTES_TOTAL NUMBER Oracle 数据库与存储系统之间交换的 I/O 字节的累计值
    IO_INTERCONNECT_BYTES_DELTA NUMBER Oracle 数据库与存储系统之间交换的 I/O 字节的增量值
    PHYSICAL_READ_REQUESTS_TOTAL NUMBER 受监控 SQL 发出的物理读 I/O 请求的累计数量
    PHYSICAL_READ_REQUESTS_DELTA NUMBER 受监控 SQL 发出的物理读 I/O 请求的增量数量
    PHYSICAL_READ_BYTES_TOTAL NUMBER 受监控 SQL 从磁盘读取的字节的累计值
    PHYSICAL_READ_BYTES_DELTA NUMBER 受监控 SQL 从磁盘读取的字节的增量值
    PHYSICAL_WRITE_REQUESTS_TOTAL NUMBER 受监控 SQL 发出的物理写 I/O 请求的累计数量
    PHYSICAL_WRITE_REQUESTS_DELTA NUMBER 受监控 SQL 发出的物理写 I/O 请求的增量数量
    PHYSICAL_WRITE_BYTES_TOTAL NUMBER 受监控 SQL 写入磁盘的字节的累计值
    PHYSICAL_WRITE_BYTES_DELTA NUMBER 受监控 SQL 写入磁盘的字节的增量值
    OPTIMIZED_PHYSICAL_READS_TOTAL NUMBER 受监控 SQL 从数据库智能闪存缓存或 Exadata 智能闪存缓存进行的物理读取的累计次数
    OPTIMIZED_PHYSICAL_READS_DELTA NUMBER 受监控 SQL 从数据库智能闪存缓存或 Exadata 智能闪存缓存进行的物理读取的增量次数
    CELL_UNCOMPRESSED_BYTES_TOTAL NUMBER 卸载到 Exadata 存储单元的未压缩字节(解压后大小)的累计值。 相关信息:请参阅 Oracle Exadata Storage Server 软件手册。
    CELL_UNCOMPRESSED_BYTES_DELTA NUMBER 卸载到 Exadata 存储单元的未压缩字节(解压后大小)的增量值。 相关信息:请参阅 Oracle Exadata Storage Server 软件手册。
    IO_OFFLOAD_RETURN_BYTES_TOTAL NUMBER 仅限智能扫描时从 Exadata 存储单元返回的字节(不包括其他数据库 I/O 字节)的累计值。 相关信息:请参阅 Oracle Exadata Storage Server 软件手册。
    IO_OFFLOAD_RETURN_BYTES_DELTA NUMBER 仅限智能扫描时从 Exadata 存储单元返回的字节(不包括其他数据库 I/O 字节)的增量值。 相关信息:请参阅 Oracle Exadata Storage Server 软件手册。
    BIND_DATA RAW(2000) 绑定数据
    FLAG NUMBER 保留列
    CON_DBID NUMBER 采样会话所在 PDB 的数据库 ID
    CON_ID NUMBER CON_DBID 标识的容器的 ID。可能值如下: 0: 此值用于包含与整个 CDB 相关的数据的行。此值也用于非 CDB 中的行。 1: 此值用于包含仅与根容器相关数据的行。 n: n 是适用于包含数据的行的容器 ID

  • 相关推荐