awr不记录物化视图重写是否发生,因其仅聚合执行后资源消耗(如逻辑读、cpu时间),不捕获优化器解析决策;需结合高逻辑读+低执行次数+mv覆盖模式筛选可疑sql,并用dbms_mview.explain_rewrite闭环验证。

AWR本身不记录“物化视图重写是否发生”,也不直接统计重写失败带来的额外开销。想定位重写失败导致的性能问题,必须把AWR当作背景数据源,配合其他诊断手段交叉验证——否则只看AWR,你会以为SQL慢是I/O或CPU的事,根本看不到“本该走MV却走了基表”这层逻辑损耗。
为什么AWR里找不到“重写失败”这个指标
AWR聚合的是执行后的资源消耗(如逻辑读、CPU时间、等待事件),不是优化器决策过程。即使一条SQL因未匹配MV而全表扫描基表,AWR只会显示db file sequential read或db file scattered read等待,不会标注“此处本可走MV”。重写是否启用,发生在硬解析阶段,而AWR不捕获解析决策树。
- DBA_HIST_SQLSTAT里只有
buffer_gets、disk_reads、elapsed_time等执行结果,没有rewrite_status字段 -
v$sql里的is_rewritten列(19c新增)只存在于当前共享池中,不会落盘进AWR快照 - 如果你依赖AWR报告里的Top SQL排序,很可能漏掉真正“被绕过MV”的语句——因为它的执行时间可能刚够进Top 30,但逻辑读已是基表量级的数倍
用AWR快速识别疑似重写失效的SQL
不靠猜测,盯住三个AWR指标组合:高逻辑读 + 低执行次数 + 出现在物化视图覆盖范围内的查询模式。这类SQL最可能是“本该重写却没重写”的候选。
- 在AWR报告的
SQL ordered by Gets部分,筛选Buffer Gets per Exec> 100,000 且Executions≤ 5 的SQL - 人工比对这些SQL的FROM子句:是否含你已建的物化视图所覆盖的表组合?例如MV定义为
SELECT time_id, region, SUM(sales) FROM sales JOIN customers USING(cust_id) GROUP BY time_id, region,而SQL里恰好有FROM sales s, customers c WHERE s.cust_id = c.cust_id GROUP BY s.time_id, c.region - 检查该SQL在
Load Profile里的Logical reads per second是否显著高于同类报表时段均值——说明它正在反复啃基表块
结合DBMS_MVIEW.EXPLAIN_REWRITE做闭环验证
AWR只能提示“可能有问题”,最终确认必须落地到重写诊断工具。别跳过这步,否则所有优化都是蒙的。
- 从AWR抓出可疑SQL文本,用
DBMS_MVIEW.EXPLAIN_REWRITE显式传入:EXEC DBMS_MVIEW.EXPLAIN_REWRITE('SELECT time_id, region, SUM(sales) FROM sales s, customers c WHERE s.cust_id = c.cust_id GROUP BY time_id, region', 'MV_SALES_REGION'); - 查
REWRITE_TABLE(需提前运行UTLXRWY.SQL创建),重点看REWRITE_MECHANISM和MESSAGE列:
→ 若为UNREWRITTEN且MESSAGE含"no suitable materialized view",基本确认结构不匹配
→ 若为FAILED且MESSAGE含"integrity violation",大概率是QUERY_REWRITE_INTEGRITY = ENFORCED但基表缺RELY约束 - 注意:该过程不改变执行计划,纯诊断;且必须在目标用户schema下执行,权限不足会静默返回
UNREWRITTEN
重写失败的真实开销藏在逻辑读膨胀里
一个典型场景:某报表SQL本应通过MV走2万逻辑读,因重写失败改走基表,实际消耗180万逻辑读。这178万差额就是“重写失败开销”,但它不会单独计费,而是摊在db file scattered read等待和buffer gets里。更隐蔽的是——如果MV带复合索引而基表没对应索引,这个开销还会引发latch: cache buffers chains争用,在AWR的Top 5 Timed Events里表现为第二名等待事件。
- 不要只对比单次SQL的
elapsed_time,要算buffer_gets / executions的倍数关系:若比同类MV加速SQL高出5–10倍,基本可断定重写未生效 - 检查MV是否建了索引:
SELECT index_name FROM dba_indexes WHERE table_name = 'MV_SALES_REGION'——没索引的MV,即使重写成功,也可能因全表扫描反而更慢 - 如果业务允许,临时把
QUERY_REWRITE_ENABLED设为FORCE并重跑SQL,再抓一次AWR快照对比逻辑读变化。若大幅下降,说明原先是成本评估拦住了重写,不是结构问题











