如何通过设置QUERY_REWRITE_DISABLE参数在Oracle中关闭物化视图的查询改写功能?
- 内容介绍
- 文章标签
- 相关推荐
本文共计941个文字,预计阅读时间需要4分钟。
相关专题内容,请直接提问,避免图片解释、避免口语化表达,不超过100字。
禁用物化视图查询改写必须关掉两个地方
只改一个地方,query rewrite 依然可能生效。oracle 的查询重写是“双开关”机制:实例级参数 + 物化视图对象级设置,二者任一开启都可能导致重写发生(尤其当 query_rewrite_enabled 设为 force 时)。所以禁用必须同步处理。
-
ALTER SYSTEM SET QUERY_REWRITE_ENABLED = FALSE;—— 全局关闭,影响所有会话;需 DBA 权限 -
ALTER MATERIALIZED VIEW mv_name DISABLE QUERY REWRITE;—— 对单个 MV 显式禁用;即使参数为TRUE,该 MV 也不会被选中 - 若已用
FORCE启用过,务必先确认当前值:SELECT VALUE FROM V$PARAMETER WHERE NAME = 'query_rewrite_enabled';,避免误判
DISABLE QUERY REWRITE 不等于 DROP,但 ALTER 不支持回退
执行 DISABLE QUERY REWRITE 后,物化视图本身仍存在、可查、可刷新,只是不再参与优化器的重写决策。但要注意:Oracle 不允许用 ALTER MATERIALIZED VIEW ... ENABLE QUERY REWRITE 把已禁用的 MV 重新启用——这条语句在 12c 及以后版本会报 ORA-30375 错误。
- 正确做法是重建:
DROP MATERIALIZED VIEW mv_name;再用带ENABLE QUERY REWRITE的语句重建 - 如果 MV 依赖物化视图日志,重建前要确认日志仍存在且结构未变,否则
REFRESH FAST可能失败 - 禁用后建议立刻执行
EXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;,清空统计缓存,防止旧执行计划残留
会话级 SET QUERY_REWRITE_ENABLED = FALSE 容易被忽略
很多应用连接池(如 UCP、Druid)会在每次获取连接时执行初始化 SQL,但未必包含 ALTER SESSION。结果就是:你在 SQL*Plus 里设了 FALSE 并验证成功,上线后应用却仍在走重写。
- 检查实际运行时的会话设置:
SELECT SYS_CONTEXT('USERENV', 'SESSIONID') sess_id, VALUE FROM V$SES_OPTIMIZER_ENV WHERE NAME = 'query_rewrite_enabled' AND SID = SYS_CONTEXT('USERENV', 'SID'); - 若发现值为
TRUE或FORCE,说明连接池没覆盖该参数;需在数据源初始化语句中显式加入ALTER SESSION SET QUERY_REWRITE_ENABLED = FALSE - 注意:
ALTER SESSION对当前会话有效,断开重连即失效,不能靠一次设置长期维持
禁用后仍看到 MATERIALIZED VIEW REWRITE 执行计划?检查完整性级别
即使参数和对象都设为禁用,QUERY_REWRITE_INTEGRITY 设为 STALE_TOLERATED 且 MV 处于 STALE 状态时,某些极端路径下优化器仍可能尝试绕过检查——这不是 bug,而是 Oracle 在高一致性级别下保留的兜底行为。
- 查当前会话完整性设置:
SELECT SYS_CONTEXT('USERENV', 'SESSIONID'), VALUE FROM V$SES_OPTIMIZER_ENV WHERE NAME = 'query_rewrite_integrity'; - 临时强制规避:在关键查询前加 hint
/*+ NO_REWRITE */,它比参数更优先,且不依赖 MV 状态 - 真正可靠的禁用组合是:
QUERY_REWRITE_ENABLED=FALSE+DISABLE QUERY REWRITE+ 应用层确保无NO_REWRITE以外的 hint 干扰
DISABLE 后还能 ENABLE 回来。一旦 MV 被禁用,基本就得重建——这点和普通表的 DISABLE CONSTRAINT 完全不同。本文共计941个文字,预计阅读时间需要4分钟。
相关专题内容,请直接提问,避免图片解释、避免口语化表达,不超过100字。
禁用物化视图查询改写必须关掉两个地方
只改一个地方,query rewrite 依然可能生效。oracle 的查询重写是“双开关”机制:实例级参数 + 物化视图对象级设置,二者任一开启都可能导致重写发生(尤其当 query_rewrite_enabled 设为 force 时)。所以禁用必须同步处理。
-
ALTER SYSTEM SET QUERY_REWRITE_ENABLED = FALSE;—— 全局关闭,影响所有会话;需 DBA 权限 -
ALTER MATERIALIZED VIEW mv_name DISABLE QUERY REWRITE;—— 对单个 MV 显式禁用;即使参数为TRUE,该 MV 也不会被选中 - 若已用
FORCE启用过,务必先确认当前值:SELECT VALUE FROM V$PARAMETER WHERE NAME = 'query_rewrite_enabled';,避免误判
DISABLE QUERY REWRITE 不等于 DROP,但 ALTER 不支持回退
执行 DISABLE QUERY REWRITE 后,物化视图本身仍存在、可查、可刷新,只是不再参与优化器的重写决策。但要注意:Oracle 不允许用 ALTER MATERIALIZED VIEW ... ENABLE QUERY REWRITE 把已禁用的 MV 重新启用——这条语句在 12c 及以后版本会报 ORA-30375 错误。
- 正确做法是重建:
DROP MATERIALIZED VIEW mv_name;再用带ENABLE QUERY REWRITE的语句重建 - 如果 MV 依赖物化视图日志,重建前要确认日志仍存在且结构未变,否则
REFRESH FAST可能失败 - 禁用后建议立刻执行
EXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;,清空统计缓存,防止旧执行计划残留
会话级 SET QUERY_REWRITE_ENABLED = FALSE 容易被忽略
很多应用连接池(如 UCP、Druid)会在每次获取连接时执行初始化 SQL,但未必包含 ALTER SESSION。结果就是:你在 SQL*Plus 里设了 FALSE 并验证成功,上线后应用却仍在走重写。
- 检查实际运行时的会话设置:
SELECT SYS_CONTEXT('USERENV', 'SESSIONID') sess_id, VALUE FROM V$SES_OPTIMIZER_ENV WHERE NAME = 'query_rewrite_enabled' AND SID = SYS_CONTEXT('USERENV', 'SID'); - 若发现值为
TRUE或FORCE,说明连接池没覆盖该参数;需在数据源初始化语句中显式加入ALTER SESSION SET QUERY_REWRITE_ENABLED = FALSE - 注意:
ALTER SESSION对当前会话有效,断开重连即失效,不能靠一次设置长期维持
禁用后仍看到 MATERIALIZED VIEW REWRITE 执行计划?检查完整性级别
即使参数和对象都设为禁用,QUERY_REWRITE_INTEGRITY 设为 STALE_TOLERATED 且 MV 处于 STALE 状态时,某些极端路径下优化器仍可能尝试绕过检查——这不是 bug,而是 Oracle 在高一致性级别下保留的兜底行为。
- 查当前会话完整性设置:
SELECT SYS_CONTEXT('USERENV', 'SESSIONID'), VALUE FROM V$SES_OPTIMIZER_ENV WHERE NAME = 'query_rewrite_integrity'; - 临时强制规避:在关键查询前加 hint
/*+ NO_REWRITE */,它比参数更优先,且不依赖 MV 状态 - 真正可靠的禁用组合是:
QUERY_REWRITE_ENABLED=FALSE+DISABLE QUERY REWRITE+ 应用层确保无NO_REWRITE以外的 hint 干扰
DISABLE 后还能 ENABLE 回来。一旦 MV 被禁用,基本就得重建——这点和普通表的 DISABLE CONSTRAINT 完全不同。
