explain_rewrite返回unrewritten时,应重点查看rewrite_mechanism和message两列:前者为判决类型,后者为人话提示;若rewrite_mechanism为no_rewrite或unrewritten,说明语义层重写链已中断。

EXPLAIN_REWRITE返回UNREWRITTEN时该查哪几列
别只看输出里有没有报错,关键盯住REWRITE_MECHANISM和MESSAGE两列。前者是判决类型,后者是人话提示。如果REWRITE_MECHANISM是NO_REWRITE或UNREWRITTEN,说明重写链在语义层就断了;如果值为TEXT_MATCH但实际没走 MV,那问题出在成本估算或统计信息上。
执行前必须先建解释表:@?/rdbms/admin/utlxmv.sql(官方脚本),再运行:EXEC DBMS_MVIEW.EXPLAIN_REWRITE('SELECT * FROM sales WHERE time_id >= DATE ''2024-01-01''', 'MV_SALES_MONTHLY');
-
MESSAGE里出现"partition key not used"→ 查询过滤的列名和 MV 分区键列名不一致(大小写、别名、双引号包裹都算不一致) -
"expression not supported"→ 查询中对分区键用了函数,比如TRUNC(time_id)而 MV 是按time_id物理列分区 -
"query rewrite disabled"→ 用户没QUERY REWRITE权限,或QUERY_REWRITE_ENABLED被设为FALSE
为什么EXPLAIN_PLAN看不到重写但EXPLAIN_REWRITE说可匹配
这是最常见的误判点:EXPLAIN PLAN 显示访问基表,不代表重写失败,只是优化器觉得走基表更便宜。而DBMS_MVIEW.EXPLAIN_REWRITE只管“能不能”,不管“划不划算”。
- 物化视图本身没收集统计信息 →
DBMS_STATS.GATHER_TABLE_STATS必须显式指定GRANULARITY => 'ALL',否则分区级基数不准 - 基表统计信息过期 → 查
USER_TAB_STATISTICS.LAST_ANALYZED,若比 MV 的晚很多,CBO 会高估基表过滤效率 - 加 hint 强制验证:
SELECT /*+ REWRITE(MV_SALES_MONTHLY) */ * FROM sales WHERE time_id >= DATE '2024-01-01';,如果执行计划立刻切到 MV 且性能提升,就是成本误判
QUERY_REWRITE_INTEGRITY设置如何影响诊断结果
这个参数不是“开/关”开关,而是重写信任等级,它直接决定EXPLAIN_REWRITE是否跳过某些校验。设成ENFORCED最严格,但要求所有基表主键都带RELY ENABLE NOVALIDATE;设成STALE_TOLERATED会绕过 STALE 状态检查,但也可能掩盖真实约束缺失。
- 若
EXPLAIN_REWRITE返回FAILED且MESSAGE含"integrity constraint not satisfied"→ 基表缺RELY约束,不是没建主键,是没声明“我信它” - 临时调成
STALE_TOLERATED后REWRITE_MECHANISM变成GENERAL→ 说明原问题确实是 MV 状态为STALE,但你不该只改参数,得查CAN_USE_LOG = 'NO'或REFRESH FAST是否真失效 - 永远不要在生产环境长期设
TRUSTED—— 它跳过所有约束验证,重写结果可能不一致
物化视图含UNION ALL时为何EXPLAIN_REWRITE直接不认
Oracle 查询重写器从不尝试拆解或合并多个 MV,也不支持任何含UNION ALL的物化视图参与重写。这不是配置或权限问题,是硬编码限制:只要DBA_MVIEWS.QUERY字段里出现UNION关键字,EXPLAIN_REWRITE必然返回UNREWRITTEN,且MESSAGE不会给出细节提示。
- 查证方式:
SELECT QUERY FROM DBA_MVIEWS WHERE MVIEW_NAME = 'MV_SALES_COMBINED';,肉眼确认是否有UNION或UNION ALL - 替代做法:把原查询按业务维度拆成多个独立 MV,例如
MV_SALES_ONLINE和MV_SALES_STORE,再让应用层分别查 - 注意:即使两个 MV 结构完全一样,Oracle 也不会自动拼接它们的结果——重写只绑定单个 MV 对象
真正容易被忽略的是:物化视图重写失败时,错误往往不在 MV 定义本身,而在查询与 MV 之间那一毫米宽的语义缝隙——列名大小写、函数包装、统计信息时间差、甚至QUERY_REWRITE_INTEGRITY的隐式行为。这些地方不报错,只静默跳过。











