物化视图不能直接move或rebuild到新表空间,因其本质是“查询快照+日志+刷新机制”的组合体,非纯数据段;唯一可靠方式是导出定义、修改tablespace后重建,并同步处理日志、索引和刷新作业。

物化视图本身不能直接 MOVE 或 REBUILD 到新表空间
Oracle 中 MATERIALIZED VIEW 是一种特殊段类型(SEGMENT_TYPE = 'TABLE'),但它底层依赖的主表、日志、索引和存储段各自独立,没有类似 ALTER MATERIALIZED VIEW ... MOVE TABLESPACE 的语法。试图执行该语句会报 ORA-00905: missing keyword 或直接报错无效命令。
真正能迁移的,是它背后实际占用空间的物理对象:
- 物化视图对应的基表段(即
dba_tables中同名的表)——可ALTER TABLE mv_name MOVE TABLESPACE new_ts - 物化视图日志(如果存在)——需单独
ALTER MATERIALIZED VIEW LOG ON base_table REBUILD TABLESPACE new_ts - 物化视图上的索引(包括主键、唯一约束生成的索引)——用
ALTER INDEX idx_name REBUILD TABLESPACE new_ts - LOB 段(若 MV 表含 CLOB/BLOB)——必须显式
ALTER TABLE mv_name MOVE LOB(col) STORE AS (TABLESPACE new_ts)
迁移前必须停用刷新并检查依赖
物化视图在刷新过程中会写入临时段、锁定基表、甚至修改日志结构。未停止刷新就操作,极易触发 ORA-12008: error in materialized view refresh path 或锁等待超时。
安全操作顺序如下:
- 确认当前刷新状态:
SELECT mview_name, last_refresh_date, refresh_mode FROM dba_mviews WHERE owner = 'U1' AND mview_name = 'MV_T1'; - 暂停自动刷新:
DBMS_MVIEW.REFRESH('MV_T1', method => 'C'); -- 先做一次完整刷新确保数据一致,再停掉调度;若用 DBMS_SCHEDULER,需DBMS_SCHEDULER.DISABLE('MV_REFRESH_JOB'); - 检查是否依赖物化视图日志:
SELECT log_table FROM dba_mview_logs WHERE master = 'BASE_TABLE';,有则需一并处理 - 确认无正在运行的查询引用该 MV(特别是开启
QUERY REWRITE的场景),否则MOVE后可能因统计信息失效或索引失效导致 SQL 执行计划突变
MOVE 主表后索引全部失效,必须重建
ALTER TABLE mv_name MOVE TABLESPACE new_ts 会重写整张表段,所有基于原 ROWID 的索引立刻变为 UNUSABLE 状态,包括主键索引、唯一约束索引、函数索引等——这不是异常,是 Oracle 明确行为。
重建时注意三点:
- 不能只重建部分索引:查
SELECT index_name, status FROM dba_indexes WHERE table_name = 'MV_T1' AND status = 'UNUSABLE';,逐个执行ALTER INDEX idx_name REBUILD TABLESPACE new_ts; - 若索引原建在 SYSTEM 或 SYSAUX 中,重建时必须指定目标表空间,否则仍落回原处
- 重建期间索引不可用,查询可能退化为全表扫描;如需减少影响,可用
REBUILD ONLINE(12cR2+),但要求表有主键或唯一约束,且期间 DML 可能短暂阻塞
SYSTEM 表空间里的物化视图要特别小心
如果物化视图误建在 SYSTEM 表空间(常见于未指定 TABLESPACE 的 CREATE 语句),迁移不是“能不能”的问题,而是“必须做”——否则 SYSTEM 持续膨胀且无法 shrink,最终引发 ORA-1653 或启动失败。
但操作权限和路径更严苛:
- 必须用 DBA 用户执行,普通用户即使有
ALTER ANY TABLE也常因缺少SELECT ANY DICTIONARY而查不到dba_mview_logs - MOVE 前先验证目标表空间配额:
SELECT username, tablespace_name, bytes/1024/1024 mb FROM dba_ts_quotas WHERE username = 'U1' AND tablespace_name = 'USERS';,没配额会报ORA-01536: space quota exceeded - 含 LOB 的物化视图在旧版本(如 10.2.0.4)上执行
MOVE LOB可能报ORA-14602,稳妥做法是用“换表法”:CREATE TABLE mv_t1_new TABLESPACE users AS SELECT * FROM mv_t1; DROP MATERIALIZED VIEW mv_t1; RENAME mv_t1_new TO mv_t1;,再重建 MV 定义
真正麻烦的从来不是语法,而是 MV 背后那一串隐式依赖:基表、日志、索引、约束、甚至其他依赖它的嵌套 MV ——漏掉任何一个,迁移后都可能表现为查询结果不一致或刷新失败。











