QUERY_REWRITE_ENABLED=FALSE是最常见未触发原因;必须同时启用全局参数(TRUE/FORCE)和物化视图级ENABLE QUERY REWRITE,且满足语义等价、状态合法、统计信息完备、权限充足等条件。

QUERY_REWRITE_ENABLED = FALSE 是最常见、最直接的“未触发”原因——它就像关掉了总闸,其余所有配置都白搭。
确认全局开关是否真正启用
Oracle 不会默认开启查询重写,必须显式设置。仅靠物化视图定义里写了 ENABLE QUERY REWRITE 不够,会话或系统级开关必须为 TRUE 或 FORCE。
- 查当前会话:运行
SELECT sys_context('userenv', 'current_schema') FROM dual;后执行SHOW PARAMETER query_rewrite_enabled;若返回FALSE,立即执行ALTER SESSION SET QUERY_REWRITE_ENABLED = TRUE; - 查系统级设置:用 DBA 账户执行
SHOW PARAMETER query_rewrite_enabled;若为FALSE,需ALTER SYSTEM SET QUERY_REWRITE_ENABLED = TRUE;(注意:FORCE会绕过物化视图自身的禁用设置,慎用) - 会话级设置可被 SQL 中的 hint 覆盖,例如
/*+ NOREWRITE */会强制跳过重写,检查应用层或 BI 工具是否注入了这类 hint
物化视图本身是否真正“可重写”
建好了不等于能用。Oracle 对物化视图对象有硬性准入条件,缺一不可。
- 创建时必须带
ENABLE QUERY REWRITE子句;若已存在但没启用,不能 ALTER 启用,必须重建或用ALTER MATERIALIZED VIEW mv_name ENABLE QUERY REWRITE;(12c+ 支持) - 查状态:
SELECT mview_name, staleness, compile_state, fast_refreshable FROM USER_MVIEWS WHERE mview_name = 'MV_NAME';——staleness必须是NOT STALE(QUERY_REWRITE_INTEGRITY=ENFORCED下),且compile_state不能是INVALID - 物化视图若含
SYSDATE、ROWNUM、DBMS_RANDOM.VALUE等非确定性函数,重写会被直接禁用,EXPLAIN_REWRITE 会返回non-deterministic function
为什么 EXPLAIN PLAN 看不到物化视图名?
执行计划里只显示基表名,说明重写根本没发生。这不是性能问题,而是语义匹配失败。
- 别只看
EXPLAIN PLAN FOR,它不反映真实执行路径;必须结合V$SQL_PLAN查该 SQL 的实际OBJECT_NAME字段,或开autotrace on explain后执行查询 - 运行
DBMS_MVIEW.EXPLAIN_REWRITE:传入你的 SQL 和 MV 名,它会明确告诉你失败原因,比如integrity violation(约束缺失)、partition key not used(分区键未在 WHERE 中直用)、no match(列别名/表达式不等价) - 典型语义断层:
UPPER(name)在 MV 中,但查询写name = 'ABC';或 MV 按TRUNC(dt)分区,查询却写dt >= DATE '2024-01-01'—— Oracle 不推导函数等价性
权限与统计信息这些“隐形门槛”
即使语法全对,缺权限或没统计信息,优化器也会放弃重写,因为它不敢赌成本估算。
- 执行重写的用户必须有
QUERY REWRITE权限(不是CREATE MATERIALIZED VIEW);跨 schema 场景下,还需SELECT ANY TABLE或具体基表SELECT权限 - 物化视图对象本身必须有统计信息:
EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => USER, tabname => 'MV_NAME', granularity => 'ALL');—— 缺失时 CBO 可能因基数估算失真而选错路径 - 基表和 MV 的统计信息时间戳最好接近;查
SELECT table_name, last_analyzed FROM user_tab_statistics WHERE table_name IN ('BASE_TABLE', 'MV_NAME');
最容易被忽略的是:物化视图日志不是可选配件,而是 FAST 刷新和重写的硬依赖;一旦 DBA_MVIEW_LOGS 里对应日志的 rowids 或 primary_key 为 N,或者日志表 status 是 INVALID,重写引擎连尝试都不会做。











