需要优先关注那些单次物理读异常偏高的 SQL,尤其是满足 Physical Reads/Executions>1000 且 Rows Processed/Executions<100 的语句。这类 SQL 通常是数据库性能瓶颈最容易出现的区域,背后常见原因通常就是全表扫描,或者查询条件选择性过低,导致索引无法有效发挥作用。

排查时先重点查看 AWR 报告中的 SQL ordered by Physical Reads 页面,但不要只机械地盯着前 3 名。很多真正拖慢 Oracle 数据库系统的 SQL,并不是执行次数最多的那批,而是执行频率不高、但单次物理读极其夸张的语句。比如某条 SQL 只执行了 2 次,总 Physical Reads 却高达 85 万,这种情况大概率就是发生了全表扫描,说明索引基本没有生效。
为什么不能只看“Top SQL by Physical Reads”排名
这个页面虽然按总物理读从高到低排序,但并不会区分具体业务类型,也无法体现执行频次差异。一条报表 SQL 扫描 10GB 历史数据,物理读高本身可能是合理的;而一条每秒执行 50 次的订单查询,每次只返回几十行却持续触发物理读,往往才是拖垮数据库性能的真正根因。
Physical Reads / Executions > 1000在 OLTP 场景下通常是非常明确的异常信号Executions = 1但Physical Reads > 500000,应优先判断是否属于夜间批处理任务,而不是直接归类为实时接口性能问题- 同一
SQL_ID在不同快照中的Executions波动非常剧烈(如从 1000 突降到 1),通常说明绑定变量取值分布不均,或者统计信息已经过期,导致执行计划不稳定 - AWR 默认每 60 分钟采样一次,会掩盖短时间内的尖峰压力——如果某 SQL 在 2 分钟内执行 3000 次、每次读 200 块,总读虽然只有 60 万,可能进不了 Top 10,但它很可能正是
db file sequential read等待事件飙升的关键原因
怎么算出真正危险的“单次高读”SQL
AWR 报告中通常只展示 Physical Reads 和 Executions 两列,因此必须手动计算两者比值。注意:如果 Executions = 0,需要直接跳过,否则计算结果没有参考意义。
- 打开 AWR 报告 → 定位到
SQL ordered by Physical Reads表格 - 对每一行计算
Physical Reads / Executions(建议借助 Excel 或文本编辑器提高效率) - 重点筛选比值 > 1000 且
Rows Processed / Executions < 100的语句——这说明每次执行只处理少量数据,却读取了大量数据块,极大概率是全表扫描叠加低选择性 WHERE 条件 - 如果某条 SQL 的
Physical Reads / Rows Processed > 10,基本可以判断访问路径已经失效,常见原因包括缺少索引、统计信息不准确、隐式类型转换等
拿到 SQL_ID 后必须立刻验证的三件事
AWR 只能提供 SQL_ID 和聚合后的统计信息,并不会直接告诉你它到底读取了哪张表、使用了什么执行计划、是否真的缺少索引。只看数字无法完成有效优化。
- 查执行计划:
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR(',重点确认大表上是否出现your_sql_id'))TABLE ACCESS FULL,以及Predicate Information中 WHERE 条件字段是否只出现在filter而没有进入access - 反查真实读取对象:使用
DBA_HIST_SEG_STAT查看该 SQL 在对应快照区间内的物理读主要集中在哪些段:SELECT owner, object_name, SUM(physical_reads) reads FROM dba_hist_seg_stat s JOIN dba_objects o ON s.obj# = o.object_id WHERE s.snap_id BETWEENbegin_snapANDend_snapAND o.owner IN ('YOUR_SCHEMA') GROUP BY owner, object_name ORDER BY reads DESC - 确认对象大小:对高物理读对象执行
SELECT bytes/1024/1024 AS mb FROM dba_segments WHERE owner = 'X' AND segment_name = 'Y',不要被分区名或视图名误导——真正需要优化的,往往是底层大表,或者缺失索引的小型配置表
最容易被忽略的一步是:没有核对 RAC 环境下的 Instance ID,误把节点 A 的局部热点当成全局数据库问题;同时也没有切换到 ASH 报告去验证调用密度,结果优化了很久,最后才发现那条“高物理读 SQL”其实一天只执行一次。
