在做数据库巡检时,或者发现数据库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_SNAPSHOTDBA_HIST_SNAPSHOT:AWR 快照基础表,记录每个快照起止时间
DBA_HIST_SQLSTAT:每个快照区间内各 SQL 的增量性能指标(
DELTA 后缀 = 快照间隔内新增值)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总共返回/处理的数据行数
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 -- 只查最近1天的AWR快照 AND EXECUTIONS_DELTA > 0 -- 过滤快照内一次都没执行的SQL ORDER BY BUFFER_GETS_DELTA DESC; -- 按逻辑读倒序,最耗资源SQL放最前面
EXECUTIONS_DELTA >0 排除当天完全没运行的 SQL,减少无效数据;带
_DELTA 的字段不是累计总值,是
两个快照之间的增量:比如每小时一次 AWR 快照,
BUFFER_GETS_DELTA = 上一次快照到本次快照之间,这条 SQL 产生的逻辑读总和。
优势:精准统计时间段内业务真实负载,不会被历史累计数据干扰。
| SQL_STATUS | 问题说明 | 优化方向 |
| 严重全表扫描 | 逻辑读远高于返回行数,大概率无索引 / 索引失效全表扫 |
1. 检查执行计划是否 FULL TABLE SCAN 2. 缺失过滤字段索引 3. 统计信息陈旧导致选错执行计划 |
| 疑似全表扫描 | 索引效率差,可能走大范围索引扫描 |
1. 优化复合索引前缀 2. 减少不带过滤条件的查询 3. 分区裁剪优化 |
| 读取正常 | 索引使用健康,每行消耗内存块少 | 无需优先优化 |
V$SQL;
ELAPSED_TIME_DELTA;DBA_HIST_SQLTEXT 拿到完整 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/ ,如需转载,请注明出处,否则将追究法律责任。