物化视图创建本地索引需满足:select列表中必须直接裸露基表分区键列(未被函数、别名、聚合或连接改变),否则报ora-14035;建索引前须设on demand刷新、启用查询重写、执行完全刷新;索引需显式声明local,且查询谓词须避免函数包裹分区键,确保执行计划中object_name含分区后缀。
不能直接像普通表那样执行 create index 就得到有效的本地索引——物化视图的本地索引有强前提约束,不满足时会报 ora-14035,且即使建成功,也可能完全不参与分区裁剪。
为什么 CREATE INDEX ... LOCAL 会报 ORA-14035
根本原因是物化视图定义中未显式包含基表的分区键列。Oracle 要求:只有当物化视图的 SELECT 列表里**直接引用了基表的分区键列(如 time_id)**,且该列未被函数包裹、未被别名覆盖、未在聚合或连接中丢失语义,才能支持在其上创建本地索引。
- 错误示例:
SELECT SUM(sales), TRUNC(time_id, 'MM') AS month FROM sales_tab GROUP BY TRUNC(time_id, 'MM')→time_id被函数处理,无法识别为分区键 - 正确写法:
SELECT time_id, SUM(sales) FROM sales_tab GROUP BY time_id→ 分区键列裸露、未变形 - 验证方式:查
USER_MVIEWS中对应物化视图的QUERY字段,确认分区键列名原样存在
创建本地索引前必须做的三件事
本地索引不是“建完就生效”,它依赖物化视图数据的物理组织与基表对齐。跳过任一环节,索引会退化为全局行为。
- 确保刷新模式是
ON DEMAND,且已启用查询重写:ENABLE QUERY REWRITE - 执行一次完整刷新:
DBMS_MVIEW.REFRESH('MV_NAME', 'C'),避免索引建在未分区或陈旧的数据段上 - 建索引语句必须显式带
LOCAL关键字,不能省略;例如:CREATE INDEX mv_sales_time_idx ON mv_sales(time_id) LOCAL
查询没走本地索引?先看执行计划里的 OBJECT_NAME
即使索引存在,优化器也可能绕过它。关键看执行计划中索引访问行的 OBJECT_NAME 是否带分区信息(如 MV_SALES_TIME_IDX P001)。如果显示为 INDEX (UNIQUE) 或无分区后缀,说明实际走了全局路径。
- 典型失效谓词:
WHERE TRUNC(time_id) = DATE '2024-01-01'→ 函数导致分区键失效 - JOIN 场景下失效:
JOIN mv_sales ON t.id = mv.id但没在WHERE或ON中传递time_id值 - 安全写法:
WHERE time_id >= DATE '2024-01-01' AND time_id → 明确范围,可裁剪
本地索引的有效性极度依赖“分区键列在物化视图定义中是否裸露”和“查询谓词是否保持其原始可比较性”——这两点稍有偏差,整个分区裁剪链就断了,索引形同虚设。











