Physical Reads高本质是索引缺失或缓存失效导致的非必要磁盘读,需结合执行计划验证TABLE ACCESS FULL、检查Physical Reads/Rows Processed比值>10、确认是否OLTP短事务异常触发,而非仅看累计读取量。

SQL ordered by Reads 消耗高,本质是物理读(Physical Reads)多,不是“读得多就一定错”,而是得看这些读是不是本该走索引却没走、或者数据根本不在缓存里被迫反复刷盘。
为什么Physical Reads会居高不下
AWR里“SQL ordered by Reads”统计的是 disk_reads(即物理读),它反映SQL执行时从磁盘实际读取的数据块数。常见成因包括:
- WHERE条件字段缺失索引,触发
TABLE ACCESS FULL,尤其在OLTP场景中单次执行读超10万块基本可判定为索引缺失 - 索引存在但统计信息过期,优化器误判选择性,仍选全表扫描
- 查询返回大量行(如报表、ETL),且结果集远超
_small_table_threshold,Oracle自动启用direct path read,跳过buffer cache——这类读也会计入Physical Reads - 表被频繁修改(DML多),导致buffer cache中数据块频繁失效,后续查询不得不重读磁盘
- RAC环境下未按
Instance ID过滤,把某节点的热点读误当作全局问题
别只盯着排序第一的SQL
AWR默认按累计 disk_reads 排序,容易漏掉真正危险的语句:
- 执行次数少(
Executions= 1 或 2)、但单次Physical Reads爆炸(比如50万+)的SQL,往往是夜间批量作业或定时报表,一次跑崩整个I/O子系统 - 对比
Physical Reads / Rows Processed:若比值 > 10,说明每返回一行平均要读10多个数据块,极大概率是索引没覆盖查询条件或回表严重 - 检查
SQL ordered by Elapsed Time是否同步偏高——如果物理读高但响应时间不长,可能是大结果集合理直读;如果又慢又读多,才是真瓶颈
怎么确认是不是索引问题
不能光看“Reads高”就建索引,得验证是否真由索引缺失导致:
- 查该SQL的执行计划:
SELECT * FROM table(DBMS_XPLAN.DISPLAY_AWR('sql_id')),重点看是否有TABLE ACCESS FULL且对应表没走已有索引 - 用
DBA_HIST_SEG_STAT查目标表的逻辑读/物理读趋势:SELECT obj#, logical_reads_total, physical_reads_total FROM dba_hist_seg_stat WHERE obj# IN (SELECT object_id FROM dba_objects WHERE object_name = 'YOUR_TABLE') AND snap_id BETWEEN &begin AND &end - 强制走索引测试:
SELECT /*+ INDEX(t idx_col) */ ... FROM t WHERE ...,再对比buffer_gets和执行时间——如果逻辑读不降反升,说明索引设计不合理(比如顺序错、未包含查询列) - 注意
INDEX FAST FULL SCAN也会产生大量db file scattered read,别把它当成“走了索引就安全了”
物理读高本身不可怕,可怕的是它出现在不该出现的地方:短事务、高频OLTP语句、单次返回几十行却读几百个块。这时候必须深挖执行计划和谓词字段的选择性,而不是直接加索引——建错一个索引,可能让DML更慢、回表更多、甚至把优化器带进死路。


















