物化视图不感知基表分区,查询重写仅依赖定义逻辑与条件匹配,与分区裁剪无关;需显式包含常用维度字段、启用查询重写权限、为日志指定独立表空间,并注意ON QUERY COMPUTATION的限制及三大硬约束。
物化视图不感知分区,别指望它自动路由到分区
oracle物化视图本身完全不识别底层基表是否做了range、list或hash分区。它只认自己select语句里写的逻辑——哪怕基表按time_id分了100个分区,物化视图也只会把结果存成一张“扁平”的物理表(或预制表)。查询能否命中物化视图,只取决于where条件是否能被查询重写器(query rewrite)匹配上,和基表分区毫无关系。
常见错误现象:EXPLAIN PLAN FOR SELECT ...后发现执行计划里仍是TABLE ACCESS FULL基表,而不是TABLE ACCESS FULL或INDEX RANGE SCAN物化视图名——说明压根没重写成功。
- 必须在物化视图定义中显式包含查询常用维度字段(如
region、time_id、product_category),且聚合粒度要覆盖实际查询的GROUP BY或WHERE组合 - 开启查询重写需确保:
QUERY_REWRITE_ENABLED=TRUE(会话级或系统级),且用户有QUERY REWRITE权限 - 若基表有分区裁剪(partition pruning),但物化视图未按相同键建模,则重写必然失败——不是性能差,而是根本不用物化视图
增量刷新依赖物化视图日志,但分区表日志有坑
要支持REFRESH FAST,必须在基表上建MATERIALIZED VIEW LOG。对分区表来说,这个日志本身不继承分区属性——它总是一张普通堆表,所有DML变更都追加进去。当基表数据量大、更新频繁时,日志表可能成为I/O热点,甚至撑爆SYSTEM表空间(如果建在默认表空间)。
实操建议:
- 为物化视图日志单独指定高性能表空间:
CREATE MATERIALIZED VIEW LOG ON sales TABLESPACE mvlog_tbs; - 日志必须包含查询中涉及的所有列,尤其是
JOIN和GROUP BY字段;漏掉ROWID或SEQUENCE会导致快速刷新失败,报错ORA-12052: cannot fast refresh materialized view - 分区表上的日志不支持
INCLUDING NEW VALUES(12cR2+除外),所以INSERT和UPDATE可刷,但DELETE后若没做COMMIT,日志可能残留旧镜像
实时物化视图(ON QUERY COMPUTATION)绕过刷新延迟,但代价明确
Oracle 12.2+ 提供的ON QUERY COMPUTATION子句,让物化视图在查询时动态合并当前基表变更(通过内部变更跟踪,非物化视图日志),实现“查到的就是最新的”。但它不是万能解药:
- 不兼容
ON COMMIT刷新,也不能和传统FAST刷新混用 - 每次查询都会触发基表扫描+变更计算,若基表本身无索引、变更量大,响应反而比刷好的物化视图更慢
- 无法用于复杂
JOIN多表场景(仅支持单表或简单连接),且不支持UNION、分析函数等高级语法 - 启用前必须确认基表已启用行移动(
ALTER TABLE sales ENABLE ROW MOVEMENT),否则创建直接报错
示例创建语句:CREATE MATERIALIZED VIEW mv_sales_rt ON QUERY COMPUTATION AS SELECT time_id, region, SUM(amount) FROM sales GROUP BY time_id, region;
分区表+物化视图组合下,最易忽略的三个硬约束
很多团队卡在最后一步:明明物化视图建好了、日志也有了、查询重写也开了,还是不走MV。往往栽在这几个隐性限制上:
-
SELECT列表中不能有SYSDATE、USER、ROWNUM等不确定性函数,否则物化视图无法被重写(即使你没在查询里用它们) - 基表若用了虚拟列(virtual column)或隐藏列(如
ORA_ROWSCN),而物化视图日志没显式包含它们,FAST刷新会静默退化为COMPLETE - 分区交换(
EXCHANGE PARTITION)操作不会自动触发物化视图刷新,必须手动执行DBMS_MVIEW.REFRESH,否则该分区对应的数据在MV里永远是旧的
真正麻烦的从来不是怎么建,而是建完之后谁来保证它持续有效——尤其当基表结构、分区策略、业务查询模式发生变更时,物化视图的定义和刷新逻辑必须同步演进,否则它就只是个占空间的“僵尸表”。











