awr中direct path read高且physical reads飙升,基本说明大表全表扫描拖垮i/o;应优先查top segments by physical reads和sql ordered by physical reads,结合执行计划确认是否真为table access full,并排查统计信息陈旧、隐式转换、分区裁剪失效等根因。

AWR里看到大量 direct path read 且 Physical Reads 飙升,基本就是大表全表扫描在拖垮I/O——但直接加索引或调PGA往往无效,得先确认是不是真该扫、为什么非扫不可、扫的时候有没有被逼着绕过缓存。
怎么从AWR快速锁定是哪个大表在全表扫描
别翻SQL Statistics里“Elapsed Time”最高的SQL。重点看两个地方:
-
Top Segments by Physical Reads:找OBJECT_TYPE = TABLE且PHYSICAL_READS显著高于其他段的行;如果同名表在Top Segments by Direct Physical Reads也排前几,基本坐实是它在走 direct path -
SQL ordered by Physical Reads:筛选Physical Reads Per Exec > 10000且Executions > 5的语句;再点开它的PLAN_HASH_VALUE,用DBMS_XPLAN.DISPLAY_AWR查执行计划,确认是否真为TABLE ACCESS FULL - 排除干扰:如果该SQL同时出现在
SQL ordered by Temp Space里,说明它可能还带排序或哈希连接,direct path read可能来自临时段而非原表
为什么加了 PARTITION 或 INDEX 还是全表扫描
AWR只告诉你“在扫”,不告诉你“为啥非扫不可”。常见卡点藏在执行计划和统计信息里:
- 执行计划中
Rows列预估远小于实际(比如估100行,实际返回50万)→ 很可能是NUM_ROWS陈旧,跑DBMS_STATS.GATHER_TABLE_STATS补统计 - 谓词含隐式转换:
WHERE to_char(create_time) = '2026-08'→ 索引失效,强制全扫;改写为create_time >= DATE '2026-08-01' AND create_time - 分区表没走分区裁剪:执行计划出现
PARTITION RANGE ALL而非SINGLE或ITERATOR→ 检查 WHERE 条件是否用了分区键,且值是否可静态评估(避免SYSDATE、绑定变量未传值等)
确认 direct path read 是不是真由全表扫描触发
这个等待事件本身不等于“坏”,但它在大表扫描场景下暴露的是更深层问题:
- 先查阈值:
SELECT ksppinm, ksppstvl FROM x$ksppi a, x$ksppcv b WHERE a.indx = b.indx AND ksppinm = '_small_table_threshold';→ 如果表大小远超该值却仍走db file scattered read,说明被强制缓存(比如ALTER TABLE ... CACHE),反而可能挤占 buffer pool - 检查是否被
parallel_force_local = TRUE锁死:即使写了/*+ parallel(t 8) */,也会退化为单节点扫描 + 缓存路径,导致物理读集中在一台实例上 - 观察
Load Profile中Physical Reads Direct和Physical Reads的比值:若前者占比 >80%,且Logical Reads/Second并不高,说明大部分读确实绕过了 buffer cache,优化方向应聚焦减少扫描量,而非调大 SGA
执行计划里看不到 Q101/Q201?那并行根本没启动
加了 /*+ parallel(t 8) */ 却没效果,不是 hint 写错,而是 Oracle 压根没进并行路径:
- 执行计划
IN-OUT列全是S->S或P->S,没有P->P→ 说明 coordinator 没分发任务给从属进程 - 查表真实并行能力:
SELECT degree, instances FROM dba_tables WHERE table_name = 'YOUR_TABLE';→ 若degree = 1或instances = 1,需先ALTER TABLE ... PARALLEL 8 - 会话级参数
parallel_force_local是隐形杀手:用SHOW PARAMETER parallel_force_local查,若为TRUE,必须ALTER SESSION SET parallel_force_local = FALSE才能跨实例
真正难的不是让扫描变快,而是让扫描消失——多数时候,业务SQL里那个“必须扫全表”的条件,其实只是开发时图省事写的 WHERE 1=1 或没传入过滤参数的绑定变量。AWR只暴露现象,根因永远在线上代码和数据分布里。











