ITPub博客

首页 > 数据库 > Oracle > 第67期 通过Oracle AWR 历史性能巡检语句判断是否存在低效全表扫描问题

第67期 通过Oracle AWR 历史性能巡检语句判断是否存在低效全表扫描问题

原创 Oracle 作者:pxbibm 时间:2026-07-02 16:39:25 0 删除 编辑

在做数据库巡检时,或者发现数据库CPU,内存压力过大时,可以通过Oracle AWR 历史性能巡检语句判断是否存在低效全表扫描问题。主要使用如下的sql进行排查问题。

SELECT SQL_ID,
       EXECUTIONS_DELTA EXEC_CNT,
       BUFFER_GETS_DELTA LOGIC_READ,
       DISK_READS_DELTA PHY_READ,
       ROWS_PROCESSED_DELTA ROWS_CNT,
       CASE
         WHEN BUFFER_GETS_DELTA > ROWS_PROCESSED_DELTA * 30 THEN
          '严重全表扫描'
         WHEN BUFFER_GETS_DELTA > ROWS_PROCESSED_DELTA * 15 THEN
          '疑似全表扫描'
         ELSE
          '读取正常'
       END SQL_STATUS
  FROM DBA_HIST_SQLSTAT S
  JOIN DBA_HIST_SNAPSHOT SH
 USING (SNAP_ID, DBID, INSTANCE_NUMBER)
 WHERE SH.BEGIN_INTERVAL_TIME >= SYSDATE - 1
   AND EXECUTIONS_DELTA > 0
 ORDER BY BUFFER_GETS_DELTA DESC;


一、整体功能概述

这条 SQL 是 Oracle AWR 历史性能巡检语句,用来查询 最近 1 天内 执行过的所有 SQL,通过 逻辑读、

返回行数自动判断 SQL 是否存在 低效全表扫描问题,按消耗资源从高到低排序,快速抓出耗 IO、耗内存的慢 SQL。

数据源: DBA_HIST_SQLSTAT + DBA_HIST_SNAPSHOT
  • DBA_HIST_SNAPSHOT:AWR 快照基础表,记录每个快照起止时间
  • DBA_HIST_SQLSTAT:每个快照区间内各 SQL 的增量性能指标( DELTA 后缀 = 快照间隔内新增值)

二、逐段拆解说明

1. 查询字段释义

SQL_ID,EXECUTIONS_DELTA EXEC_CNT,        -- 当前快照区间,这条SQL总共执行次数
BUFFER_GETS_DELTA LOGIC_READ,     -- 快照内总逻辑读(内存读,衡量SQL消耗CPU/缓存的核心指标)
DISK_READS_DELTA PHY_READ,        -- 快照内总物理读(磁盘IO,越大越慢)
ROWS_PROCESSED_DELTA ROWS_CNT,    -- 快照内这条SQL总共返回/处理的数据行数

2. 核心判断逻辑(全表扫描识别)

CASE 
    WHEN BUFFER_GETS_DELTA > ROWS_PROCESSED_DELTA * 30 THEN '严重全表扫描'
    WHEN BUFFER_GETS_DELTA > ROWS_PROCESSED_DELTA * 15 THEN '疑似全表扫描'
ELSE '读取正常'END SQL_STATUS

计算公式: 单次平均每行消耗逻辑读 = 总逻辑读 / 总行数

逻辑:

  1. 一条走优质索引的 SQL,读取少量数据就能返回结果, 每行逻辑读很低(通常个位数)
  2. 如果是全表扫描:遍历大量数据块才返回少量行,逻辑读会远大于返回行数
判定标准:
  • 总逻辑读 > 总行数 ×30 → 严重全表扫描(极高资源浪费,必须优化)
  • 总逻辑读 > 总行数 ×15 → 疑似全表扫描(索引失效、索引选择性差、范围扫描过大)
  • 其余:索引使用正常

3. 关联与过滤条件

FROM DBA_HIST_SQLSTAT S
JOIN DBA_HIST_SNAPSHOT SH USING(SNAP_ID,DBID,INSTANCE_NUMBER)
WHERE SH.BEGIN_INTERVAL_TIME >= SYSDATE - 1  -- 只查最近1天的AWR快照
  AND EXECUTIONS_DELTA > 0                  -- 过滤快照内一次都没执行的SQL
ORDER BY BUFFER_GETS_DELTA DESC;            -- 按逻辑读倒序,最耗资源SQL放最前面
  • 关联快照表是为了通过时间过滤,只看近一天业务负载;
  • EXECUTIONS_DELTA >0 排除当天完全没运行的 SQL,减少无效数据;
  • 排序逻辑:逻辑读是 Oracle 衡量 SQL 负载最核心指标,优先排查 TOP 耗资源 SQL。

三、关键概念:DELTA 增量字段

带 _DELTA 的字段不是累计总值,是 两个快照之间的增量:比如每小时一次 AWR 快照,

BUFFER_GETS_DELTA = 上一次快照到本次快照之间,这条 SQL 产生的逻辑读总和。

优势:精准统计时间段内业务真实负载,不会被历史累计数据干扰。

四、输出结果怎么看(实战解读)


SQL_STATUS 问题说明 优化方向
严重全表扫描 逻辑读远高于返回行数,大概率无索引 / 索引失效全表扫

1. 检查执行计划是否 FULL TABLE SCAN

2. 缺失过滤字段索引

3. 统计信息陈旧导致选错执行计划

疑似全表扫描 索引效率差,可能走大范围索引扫描

1. 优化复合索引前缀

2. 减少不带过滤条件的查询

3. 分区裁剪优化

读取正常 索引使用健康,每行消耗内存块少 无需优先优化

五、局限与补充说明

  1. 只看 AWR 历史数据:AWR 默认每小时采样,最长保留 8 天,实时慢 SQL 需要查 V$SQL;
  2. 判定规则是经验阈值:15、30 倍是人为经验值,大数据分页、聚合统计 SQL 本身逻辑读高会误判,需结合执行计划复核;
  3. 只统计增量指标,无法看单次执行耗时,如需单次耗时需要结合 ELAPSED_TIME_DELTA;
  4. 不分业务用户,如需按用户 / 模块过滤,可关联 DBA_HIST_SQLTEXT 拿到完整 SQL 文本。

六、扩展优化版本(常用补充)

如需直接看到 SQL 原文、单次平均耗时,可追加字段:
SELECT S.SQL_ID,
       T.SQL_TEXT,
       EXECUTIONS_DELTA EXEC_CNT,
       ROUND(ELAPSED_TIME_DELTA / EXECUTIONS_DELTA / 1000) AVG_ELAPSED_MS,
       BUFFER_GETS_DELTA LOGIC_READ,
       DISK_READS_DELTA PHY_READ,
       ROWS_PROCESSED_DELTA ROWS_CNT,
       CASE
         WHEN BUFFER_GETS_DELTA > ROWS_PROCESSED_DELTA * 30 THEN
          '严重全表扫描'
         WHEN BUFFER_GETS_DELTA > ROWS_PROCESSED_DELTA * 15 THEN
          '疑似全表扫描'
         ELSE
          '读取正常'
       END SQL_STATUS
  FROM DBA_HIST_SQLSTAT S
  JOIN DBA_HIST_SNAPSHOT SH
 USING (SNAP_ID, DBID, INSTANCE_NUMBER)
  LEFT JOIN DBA_HIST_SQLTEXT T
    ON S.SQL_ID = T.SQL_ID
 WHERE SH.BEGIN_INTERVAL_TIME >= SYSDATE - 1
   AND EXECUTIONS_DELTA > 0
 ORDER BY BUFFER_GETS_DELTA DESC;
七、案例分析

通过dbms_xplan.display_awr查看表的执行计划,分析后,几乎SQL_STATUS列是“严重全表扫描”,表的执行计划中都有

全表扫描,也是我们重点需要关注优化的sql。



来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/12798004/viewspace-3175090/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
Oracle ACE。ACOUG核心成员,Oracle用户组年轻专家。熟悉Oracle的体系结构,擅长Oracle数据库架构规划、SQL优化、OWI方面性能的优化。曾服务于航天、航空、机车、大型制造行业数据库的维护以及系统开发工作,开发过基于Oracle数据库的大型ERP系统。
  • 博文量
    345
  • 访问量
    2477883