Oracle物化视图未被分区改写,主因是QUERY_REWRITE_ENABLED关闭、MV状态非VALID/STALE、分区表达式不一致或约束缺失;需检查开关、状态、语义一致性及约束完整性。

Oracle 查询优化器没选物化视图做分区改写,不是它“不支持”,而是重写机制根本没触发——物化视图连被考虑的资格都没有。
QUERY_REWRITE_ENABLED 被关了或会话级覆盖了
这是最常被忽略的硬性开关。只要 QUERY_REWRITE_ENABLED 是 FALSE(哪怕只在当前会话),优化器连看都不会看物化视图一眼。
- 检查系统级设置:
SELECT value FROM v$parameter WHERE name = 'query_rewrite_enabled',必须是TRUE - 确认当前会话没被覆盖:
SELECT sid, name, value FROM v$ses_optimizer_env WHERE sid = SYS_CONTEXT('USERENV', 'SID') AND name = 'query_rewrite_enabled',若返回FALSE,说明ALTER SESSION SET QUERY_REWRITE_ENABLED = FALSE生效了 -
QUERY_REWRITE_INTEGRITY设为ENFORCED时,还要求基表有已验证的主键/外键约束,缺一个就静默跳过
DBMS_MVIEW.EXPLAIN_REWRITE 显示 QSM-01150 或 QSMQT_UNREWRITE
这不是执行计划问题,是语义校验失败。优化器在重写前就判定“不能用”,压根不会进成本估算阶段。
-
QSM-01150: no suitable materialized view found:常见于分区键表达式不一致,比如 MV 按TRUNC(sale_date)分区,而查询写sale_date >= DATE '2024-01-01',Oracle 不推导等价性 -
QSMQT_UNREWRITE:说明重写引擎识别到语义断层,比如物化视图 SELECT 列用了UPPER(name),但查询 WHERE 条件直接写name = 'ABC',即使结果相同也不匹配 - 运行
DBMS_MVIEW.EXPLAIN_REWRITE后查PLAN_TABLE中的MSGTXT字段,比猜快得多
执行计划里 OBJECT_NAME 是基表名,且没出现 pstart/pstop
这说明重写没发生,但你还以为是“选错了执行路径”。真正该盯的是:物化视图有没有被访问?
- 用
EXPLAIN PLAN FOR SELECT ...后查PLAN_TABLE,确认OBJECT_NAME字段是否为物化视图物理名(如MV_SALES_MONTHLY) - 如果
OPERATION是TABLE ACCESS FULL且OBJECT_NAME是基表(如SALES),那重写根本没启动 -
pstart/pstop只出现在物化视图本身被访问且已分区时;如果 MV 是单段堆表,这两个字段天然为空,和“剪枝失败”无关
物化视图状态是 STALE 或 INVALID,但没被主动刷新或编译
优化器默认不信任陈旧或损坏的物化视图。状态不是“看起来正常”就行,得是数据库内部认定的可用状态。
- 查状态:
SELECT mview_name, staleness, status FROM user_mviews WHERE mview_name = 'YOUR_MV' -
staleness = 'STALE':数据未刷新,QUERY_REWRITE_INTEGRITY = ENFORCED下直接禁用重写 -
status = 'INVALID':不是刷新问题,是依赖解析失败(比如基表删了列),ALTER MATERIALIZED VIEW ... COMPILE常报ORA-04063,必须先修复基表结构或重建 MV - 手动刷新后,别忘了
DBMS_STATS.GATHER_TABLE_STATS更新统计信息,否则 CBO 仍可能因基数误判放弃使用
真正卡住重写的,往往不是“怎么建索引”或“怎么分区”,而是元数据层面的硬性条件没满足——开关、状态、表达式一致性、约束完整性,四者缺一不可。调优前先跑一遍 DBMS_MVIEW.EXPLAIN_REWRITE 和 SELECT ... FROM user_mviews,比反复改 SQL 有用得多。











