不能直接迁移SYSTEM表空间,但必须将误建其中的业务表、索引、LOB等对象迁出,否则SYSTEM持续膨胀且无法收缩,终致数据库性能崩溃。
不能直接迁移system表空间本身,但可以安全地把误建在system里的业务表、索引、lob等对象挪出去——这是生产库必须做的“清淤”操作,否则system会持续膨胀、无法收缩,最终拖垮整个库。
为什么不能动SYSTEM表空间,却要动它里面的表
SYSTEM表空间存储数据字典、系统回滚段、核心Oracle元数据,数据库启动时强依赖它。Oracle明确禁止对SYSTEM做ALTER TABLESPACE ... RENAME DATAFILE或OFFLINE操作。但用户创建的表如果没指定TABLESPACE子句,默认就会落到SYSTEM里——这属于误用,必须修正。
常见错误现象:
- 查询
SELECT owner, segment_name FROM dba_segments WHERE tablespace_name = 'SYSTEM' AND owner NOT IN ('SYS','SYSTEM','DBSNMP')返回大量业务用户表 -
dba_free_space中SYSTEM空闲块极少,且dba_segments显示大量小碎片 - 执行
ALTER TABLE ... MOVE TABLESPACE users时报错ORA-01702(仅对当前用户对象有效)或ORA-00942(权限不足)
MOVE和REBUILD命令的实际写法与权限要点
操作必须以拥有ALTER ANY TABLE和ALTER ANY INDEX权限的用户(如DBA)执行,不能用普通业务用户连过去直接跑脚本。
关键操作清单:
- 普通表迁移:
ALTER TABLE schema_name.table_name MOVE TABLESPACE target_tablespace; - 带主键/约束的表:MOVE后索引失效,需手动重建,不能跳过
- 索引迁移:
ALTER INDEX schema_name.index_name REBUILD TABLESPACE target_tablespace; - 含LOB字段的表:必须单独处理LOB段,否则MOVE只搬表结构不搬LOB数据:
ALTER TABLE schema_name.table_name MOVE LOB(lob_column) STORE AS (TABLESPACE target_tablespace); - 分区表:需对每个分区逐个执行
MOVE PARTITION p1 TABLESPACE ts_name,不能直接MOVE整表
注意:MOVE会重写整张表,期间该表不可DML(除非加ONLINE关键字,但11g及以前不支持),务必安排在维护窗口。
SYSTEM里有LOB或IOT表时的特殊处理路径
LOB对象(尤其是CLOB/BLOB)在SYSTEM里会形成独立段,且MOVE LOB命令对某些旧版本(如10.2.0.4)可能报ORA-14602。IOT表(索引组织表)则根本不能MOVE,只能重建。
稳妥做法是“换表法”:
- 重命名原表:
ALTER TABLE schema.old_table RENAME TO old_table_bak; - 用
CREATE TABLE new_table TABLESPACE target_ts AS SELECT * FROM old_table_bak;建新表(自动继承LOB存储位置) - 重建约束、索引、触发器(需提前导出DDL)
- 验证数据一致性后,
DROP TABLE old_table_bak;
这个过程绕开了所有MOVE限制,但要求目标表空间有足够空间容纳双份数据。
迁移后必须验证的三件事
很多人MOVE完就以为结束了,结果上线后应用报错找不到索引或LOB读取失败。
必须立刻检查:
- 表归属:
SELECT tablespace_name FROM dba_tables WHERE owner='SCHEMA' AND table_name='TBL';确认已不在SYSTEM - 索引状态:
SELECT status FROM dba_indexes WHERE table_owner='SCHEMA' AND table_name='TBL';应为VALID,不是UNUSABLE - LOB段位置:
SELECT tablespace_name FROM dba_lobs WHERE owner='SCHEMA' AND table_name='TBL';确保LOB也已迁移
最容易被忽略的是:MOVE表后,原来基于该表的物化视图日志、高级队列(AQ)表、审计策略绑定对象不会自动更新,这些需要单独排查并重新配置。


















