query_rewrite_enabled=true仅启动重写检查流程,不保证重写发生;真正决定能否重写的四层过滤器是物化视图定义(需含enable query rewrite)、状态、语义匹配和会话级覆盖。

query_rewrite_enabled 参数设为 TRUE 后查询仍不走物化视图,根本原因不是参数没生效,而是它只控制“是否进入重写候选池”,真正决定能否重写的,是物化视图定义、状态、语义匹配和会话级覆盖这四层过滤器——任何一层失败,优化器就直接跳过。
query_rewrite_enabled=TRUE 是开关,不是保证
这个参数只是允许优化器启动重写检查流程。它不保证重写一定发生,也不影响物化视图本身是否可用。常见误解是“开了就能用”,实际中即使参数为 TRUE,执行计划里依然只扫基表,说明重写在后续环节被拦下了。
- 查当前值必须用
SELECT VALUE FROM V$PARAMETER WHERE NAME = 'query_rewrite_enabled'—— 返回字符串'TRUE'才算生效,'FALSE'或空值都无效 - 全局设置需 DBA 权限:
ALTER SYSTEM SET QUERY_REWRITE_ENABLED = TRUE;但 Spring Boot 等应用连接池复用连接后,不会自动执行ALTER SESSION,生产环境常因未显式开启会话级参数而失效 -
FORCE模式可绕过成本评估(强制尝试重写),但它不能修复语义不匹配或 MV 状态非法等硬性问题
物化视图本身没带 ENABLE QUERY REWRITE 子句
这是最隐蔽也最致命的漏项。只要建 MV 时没写 ENABLE QUERY REWRITE,哪怕参数全开、结构再匹配,优化器连看都不会看它一眼——它压根不在候选列表里。
- 错误写法:
CREATE MATERIALIZED VIEW mv_sum AS SELECT ...(缺子句) - 正确写法:
CREATE MATERIALIZED VIEW mv_sum ENABLE QUERY REWRITE AS SELECT ... - 已存在的 MV 无法用
ALTER MATERIALIZED VIEW ... ENABLE QUERY REWRITE补救(Oracle 不支持),只能DROP后重建 -
/*+ REWRITE */hint 在没启用对象级重写的 MV 上完全无效,不是“提示不够强”,而是该 MV 被优化器直接忽略
QUERY_REWRITE_INTEGRITY 设置导致静默跳过
默认值 ENFORCED 要求物化视图数据与基表严格一致,且依赖基表有已验证(VALIDATED)的主键/外键约束、存在物化视图日志。任一缺失,重写就静默失败——执行计划里看不到任何提示,EXPLAIN PLAN 也只显示基表访问。
- 验证当前设置:
SHOW PARAMETER query_rewrite_integrity - 临时测试可设为
STALE_TOLERATED(允许 stale 状态下重写)或TRUSTED(跳过一致性校验),但后者需 DBA 手动保障刷新及时性 - 注意:
FORCE不是QUERY_REWRITE_INTEGRITY的合法值,设错会报错 - 分区表上尤其敏感:若 MV 状态为
STALE,而QUERY_REWRITE_INTEGRITY = ENFORCED,重写直接禁用,哪怕STALENESS显示为NOT STALE也可能因约束未VALIDATED被拒
DBMS_MVIEW.EXPLAIN_REWRITE 才是唯一可信诊断入口
别信 EXPLAIN PLAN 是否出现 MV 名字,那只是执行计划快照,可能被缓存或误导。真正判断重写是否被考虑,必须调用 Oracle 内置诊断过程:
- 先运行:
EXEC DBMS_MVIEW.EXPLAIN_REWRITE('SELECT * FROM sales WHERE time_id >= DATE ''2026-01-01''', 'MV_SALES_BY_MONTH') - 查结果表
REWRITE_TABLE(需提前运行UTLXRWY.SQL创建),重点看REWRITE_MECHANISM和MESSAGE字段:NO_REWRITE+integrity violation或partition key not used直接定位根因 - 常见 MESSAGE 值:
stale data(状态问题)、no match(语义不匹配)、expression not supported(用了 TRUNC/UPPER 等函数) - 这个过程不执行 SQL,只做逻辑推演,结果稳定可靠;而
V$SQL_PLAN只反映某次真实执行路径,受绑定变量、统计信息变化干扰大
最容易被忽略的是:物化视图状态为 STALE 时,QUERY_REWRITE_INTEGRITY = ENFORCED 会直接关闭重写通道,但 USER_MVIEWS.STALENESS 字段可能仍显示 NOT STALE——因为 Oracle 对“stale”的判定还依赖物化视图日志是否启用、基表约束是否 RELY 等隐藏条件。不跑 EXPLAIN_REWRITE,永远不知道它到底卡在哪一层。











