DBMS_ADVISOR不验证物化视图重写是否生效,仅生成创建建议;必须用DBMS_MVIEW.EXPLAIN_REWRITE逐项诊断阻断原因并人工核对状态、约束、日志等运行时条件。

DBMS_ADVISOR 本身不直接评估物化视图是否会被查询重写使用,它只负责生成物化视图建议(如用 SQLACCESS_ADVISOR),而重写是否生效必须靠 DBMS_MVIEW.EXPLAIN_REWRITE 验证——这是最常被混淆的起点。
为什么不能用 DBMS_ADVISOR 查重写是否生效
DBMS_ADVISOR 的职责是“设计优化”,不是“执行验证”。它调用 SQLACCESS_ADVISOR 时只分析 SQL 结构、统计信息和负载模式,输出“该建哪些 MV”或“该补哪些日志”,但完全不接触当前会话的 QUERY_REWRITE_ENABLED 状态、约束验证情况、物化视图新鲜度等运行时条件。
常见误操作:跑完 QUICK_TUNE 后直接看 DBA_ADVISOR_RECOMMENDATIONS,发现有 CREATE MATERIALIZED VIEW 就以为重写自动生效——结果 EXPLAIN PLAN 里还是扫基表。
-
DBMS_ADVISOR输出的是“静态建议”,不反映真实执行路径 - 它不会检查
USER_MVIEWS.STALENESS是否为NOT STALE - 它对
QUERY_REWRITE_INTEGRITY = ENFORCED下缺失的VALIDATED约束毫无提示
真正该用 DBMS_MVIEW.EXPLAIN_REWRITE 验证重写
这个过程才是 Oracle 官方指定的、唯一能告诉你“这条 SQL 到底能不能走 MV”的诊断工具。它模拟优化器决策链,逐条返回阻断原因。
执行前确保已创建 REWRITE_TABLE(若未建,先运行 @?/rdbms/admin/utlxrw.sql):
EXEC DBMS_MVIEW.EXPLAIN_REWRITE( query => 'SELECT d.dname, COUNT(e.empno) FROM dept d, emp e WHERE d.deptno = e.deptno GROUP BY d.dname', mview => 'MV_DEPT_EMP_CNT' );
然后查结果:
SELECT message, rewrite_reason FROM REWRITE_TABLE;
关键输出含义:
-
message = 'QSM-01150'+rewrite_reason含missing constraints→ 基表缺 VALIDATED 主键/外键 -
message = 'QSM-01102'→ 物化视图状态为STALE或FAILED,且QUERY_REWRITE_INTEGRITY不允许用陈旧数据 -
message = 'QSM-01104'→ 查询用了物化视图里没有的列或非确定性函数(如SYSDATE) -
message = 'QSM-01109'→ 物化视图没启用ENABLE QUERY REWRITE,或会话级QUERY_REWRITE_ENABLED = FALSE
DBMS_ADVISOR 的建议必须人工核对才能用于重写
从 DBA_ADVISOR_RECOMMENDATIONS 拿到的 CREATE MATERIALIZED VIEW 脚本,只是起点,不是终点。直接执行可能建出无法被重写的 MV。
必须逐项确认:
- 若建议含
FAST REFRESH,立刻查USER_MVIEW_LOGS:对应基表是否有日志?且日志是否包含所有 SELECT 中引用的列(SEQUENCE(col1, col2))? - 若建议含聚合(
COUNT(*),SUM()),日志必须带INCLUDING NEW VALUES,否则REFRESH FAST报ORA-12004 - 建 MV 语句末尾必须显式加
ENABLE QUERY REWRITE,不能依赖系统默认 - 建完立即执行
DBMS_STATS.GATHER_TABLE_STATS对 MV 本身收集统计信息,否则优化器因成本估算失真而弃用
最容易被跳过的环节是:建完 MV 后没验证它的 STALENESS 和 QUERY_REWRITE_ENABLED 状态,就去跑报表 SQL。此时哪怕所有配置都对,只要 STALENESS = UNKNOWN 或 QUERY_REWRITE_ENABLED = FALSE(会话级覆盖),重写就静默失效——而 DBMS_ADVISOR 根本不会提醒你这点。


















