物化视图本地索引必须显式包含基表分区键列才能创建并生效,否则报ORA-14035;需配合ENABLE QUERY REWRITE、ON DEMAND刷新及准确谓词才能触发分区裁剪与查询重写。
物化视图本地索引必须建在分区键上才能生效
oracle 物化视图本身不支持直接分区,但若其基表已分区,且物化视图定义中包含分区键列(如按 time_id 分区的表,物化视图 select 中也包含 time_id),则可创建本地索引。否则 create index ... local 会报错 ora-14035: invalid partition key specified。
关键判断点:执行 SELECT * FROM USER_MVIEWS WHERE MVIEW_NAME = 'YOUR_MV',确认 CONTAINERS 和 QUERY_REWRITE_ENABLED 字段是否为 YES,更重要的是检查物化视图查询文本里是否显式引用了基表的分区键列——这是本地索引能被识别的前提。
CREATE INDEX LOCAL 必须配合物化视图的分区组织方式
本地索引不是“自动适配”的。即使物化视图底层基于分区表,也要确保物化视图刷新后数据物理分布与基表分区对齐,否则本地索引会退化为全局索引行为,失去分区裁剪能力。
实操要点:
- 物化视图需使用
ON DEMAND刷新,并指定ENABLE QUERY REWRITE - 建本地索引前,先用
DBMS_MVIEW.REFRESH完整刷新一次,避免索引建立在陈旧或未分区的数据段上 - 索引语句必须明确写
LOCAL,不能省略;例如:CREATE INDEX mv_sales_time_idx ON sales_mv(time_id) LOCAL;
- 若基表是
RANGE分区,物化视图本地索引也会按相同time_id范围切分;但 Oracle 不校验分区边界是否完全一致,靠人工保证
查询时没走本地索引?检查谓词是否触发分区裁剪
即使本地索引存在,查询仍可能全扫所有分区索引片——根本原因是 WHERE 条件未提供足够确定的分区键值,导致优化器无法排除分区。
典型失效场景:
- WHERE 中用
time_id >= TO_DATE('2024-01-01', 'YYYY-MM-DD')—— 可裁剪,走对应分区的本地索引 - WHERE 中用
TRUNC(time_id) = DATE '2024-01-01'—— 函数导致分区键失效,无法裁剪,退化为扫描全部本地索引片 - JOIN 物化视图时未在 ON 条件中传递分区键值,或使用了非等值连接
- 执行计划中看到
INDEX RANGE SCAN但 OBJECT_NAME 是INDEX (UNIQUE)或无分区信息,说明实际走了全局索引路径
本地索引 + QUERY REWRITE 的组合才有加速效果
单建本地索引对物化视图自身查询有帮助,但真正发挥价值是在重写查询(query rewrite)场景下:当用户查基表,Oracle 自动路由到物化视图,并利用其本地索引完成快速定位。
必须打开的开关:
- 会话级:
ALTER SESSION SET QUERY_REWRITE_ENABLED = TRUE; - 物化视图创建时带
ENABLE QUERY REWRITE - 基表和物化视图都需分析统计信息:
DBMS_STATS.GATHER_TABLE_STATS,否则优化器可能忽略重写 - 检查重写是否生效:
EXPLAIN PLAN FOR SELECT ...后查PLAN_TABLE,看OBJECT_NAME是否为物化视图名,且操作为INDEX RANGE SCAN+ 显示具体分区名(如SYS_P123)
分区本地索引不会自动提升物化视图刷新性能,反而可能拖慢增量刷新(FAST 模式需维护索引)。如果只为了加速查询重写,且基表分区合理,这个权衡通常值得——但别忘了,索引本身要占空间,且每个分区都有独立的索引段,监控 USER_IND_PARTITIONS 才知道实际开了多少片。











