on prebuilt table 是将已存在普通表登记为物化视图存储容器的机制,解决自动建表导致的压缩、分区、索引等策略受限及历史数据复用问题,仅支持 complete on demand 刷新。

ON PREBUILT TABLE 是什么,它解决什么问题
ON PREBUILT TABLE 不是创建新表,而是把一个已存在的普通表“登记”为物化视图的存储容器。核心作用是:避免 CREATE MATERIALIZED VIEW 自动建表带来的结构限制(比如不能自定义压缩、分区、索引策略),也方便迁移或复用已有历史数据。
它只适用于 REFRESH COMPLETE ON DEMAND 场景——即你手动触发全量刷新,且不依赖快速刷新(FAST)机制。一旦用了 ON PREBUILT TABLE,Oracle 就不会管理表结构变更,所有 DDL(如加列、改类型)必须由你手动同步到基表和物化视图定义中。
创建前必须满足的 4 个硬性条件
- 已存在一张普通表,表名、列名、列顺序、数据类型、长度/精度/刻度,必须与物化视图查询完全一致
- 该表不能有主键、唯一约束、外键、CHECK 约束(物化视图元数据会接管一致性校验)
- 表中数据需逻辑上符合物化视图查询结果(否则首次
REFRESH 可能报 ORA-12008: error in materialized view refresh path)
- 用户对这张表必须有
SELECT 权限,且拥有 CREATE MATERIALIZED VIEW 系统权限
REFRESH 可能报 ORA-12008: error in materialized view refresh path) SELECT 权限,且拥有 CREATE MATERIALIZED VIEW 系统权限 常见错误现象:ORA-12082: "schema.table" must not be a primary key or unique key table —— 其实就是表上有主键或唯一约束,删掉再试。
语法要点和典型写法
关键在于:物化视图定义里不写 AS SELECT ...,而是显式指定预建表,并用 ON PREBUILT TABLE 声明绑定关系。
CREATE MATERIALIZED VIEW mv_emp_dept ON PREBUILT TABLE REFRESH COMPLETE ON DEMAND ENABLE QUERY REWRITE AS SELECT e.empno, e.ename, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno;
注意:
-
ON PREBUILT TABLE必须紧接在物化视图名之后,不能换行或加逗号 -
REFRESH子句必须明确写成COMPLETE ON DEMAND;FAST或ON COMMIT会直接报错 -
ENABLE QUERY REWRITE可选,但启用后需确保物化视图日志等配套不存在冲突(预建表本身不支持快速刷新,所以日志无意义)
如果查询含表达式(如 UPPER(ename)),对应预建表字段也必须是 VARCHAR2 类型且长度足够,不能是 CHAR——隐式转换可能让刷新失败。
刷新时容易被忽略的细节
DBMS_MVIEW.REFRESH 刷新预建表物化视图时,Oracle 实际执行的是「TRUNCATE + INSERT APPEND」,不是 merge。这意味着:
- 表上不能有启用的
BEFORE/AFTER ROW触发器(会报ORA-32313) - 如果表启用了行移动(
ENABLE ROW MOVEMENT)或有 Flashback Data Archive,需提前评估是否兼容 - 若预建表带
COMPRESS或PARTITION,刷新后数据仍保持这些属性,但 Oracle 不校验分区键是否匹配查询谓词 - 首次刷新前建议手动执行一次
EXEC DBMS_MVIEW.REFRESH('MV_EMP_DEPT', 'C')并查DBA_MVIEWS的STALENESS字段是否变成UP-TO-DATE
复杂点在于:一旦基表结构变化(比如 emp 表新增 salary 列),你不仅要改物化视图定义(重新 CREATE OR REPLACE),还得手动 ALTER TABLE 预建表加列,否则下次刷新直接失败。这种耦合是 ON PREBUILT TABLE 模式绕不开的维护成本。











