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(快照历史)中选取数据。
-
关联条件为sq.snap_id = sn.snap_id。
-
筛选条件:
-
每个快照周期内执行次数大于10(sq.executions_delta > 10),这是为了排除执行次数太少导致的偶然性。
-
每个快照周期内总耗时大于0(sq.elapsed_time_delta > 0)。
-
快照开始时间在最近30天内(sn.begin_interval_time > SYSDATE - 30)。
-
-
按照SQL_ID和计划哈希值(plan_hash_value)分组,这样同一个SQL语句如果执行计划不同(即不同plan_hash_value)会被分开统计。
-
分组后,只选择出现在至少3个不同快照周期中的SQL(COUNT(DISTINCT sq.snap_id) >= 3)。
-
计算指标:
-
period_count: 该SQL出现在多少个不同的快照周期中。
-
first_seen: 该SQL第一次出现的时间(最早快照开始时间)。
-
last_seen: 该SQL最后一次出现的时间(最晚快照结束时间)。
-
min_elapsed_sec: 每个快照周期内,每次执行的平均耗时(秒)的最小值。注意:elapsed_time_delta是微秒,除以1000000得到秒。
-
max_elapsed_sec: 每个快照周期内,每次执行的平均耗时(秒)的最大值。
-
perf_variance: 性能波动,即最大平均耗时除以最小平均耗时。如果最小平均耗时为0,则除数为NULL,结果为NULL。
-
stability: 根据perf_variance的值判断稳定性。如果波动大于5倍,标记为“严重退化”;大于2倍,标记为“轻微退化”;否则为“稳定”。
-
-
结果按照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个不同的监控周期
-
最好的时候平均执行0.5秒
-
最差的时候平均执行3.0秒
-
性能波动了6倍,属于严重退化
-
需要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 |