不能将小文件表空间升级为大文件表空间,因其file type在创建时即固化于元数据中且不可更改;必须通过新建bigfile表空间并逐对象迁移完成逻辑转换。

不能直接把小文件表空间(smallfile tablespace)“升级”成大文件表空间(bigfile tablespace)。Oracle 不支持 ALTER TABLESPACE … CONVERT TO BIGFILE 这类操作 —— 表空间的 file type(smallfile / bigfile)在创建时就固定了,后续不可更改。
为什么不能 ALTER TABLESPACE … CONVERT TO BIGFILE
表空间的 bigfile 属性是元数据级硬约束,写入 sys.ts$ 表后即锁定。你查 dba_tablespaces 里的 bigfile 列,值为 'NO' 就说明它永远只能是 smallfile;试图用 DDL 修改该属性会报 ORA-02199 或直接语法不识别。
常见误操作包括:
- 执行
ALTER TABLESPACE users CONVERT TO BIGFILE→ 报错ORA-00922: missing or invalid option - 用
CREATE BIGFILE TABLESPACE ... AS SELECT想“复制并转类型” → 语法非法,AS SELECT不适用于表空间创建
正确迁移路径:重建 + 数据搬迁
必须新建一个 bigfile 表空间,再把原 smallfile 表空间中的对象逐个搬过去。整个过程本质是“逻辑迁移”,不是物理文件转换。
关键步骤如下:
- 创建目标 bigfile 表空间:
CREATE BIGFILE TABLESPACE new_big_tbs DATAFILE '/u02/oradata/db/new_big_tbs.dbf' SIZE 1G AUTOEXTEND ON NEXT 100M MAXSIZE UNLIMITED; - 确认原表空间中所有段归属:
SELECT owner, segment_name, segment_type FROM dba_segments WHERE tablespace_name = 'OLD_SMALL_TBS'; - 对每张表执行:
ALTER TABLE owner.table_name MOVE TABLESPACE new_big_tbs;(含 LOB 需额外处理:MOVE LOB(col) STORE AS (TABLESPACE new_big_tbs)) - 对每个索引执行:
ALTER INDEX owner.idx_name REBUILD TABLESPACE new_big_tbs; - 更新用户默认表空间(如需):
ALTER USER user_name DEFAULT TABLESPACE new_big_tbs; - 验证无残留:
SELECT * FROM dba_segments WHERE tablespace_name = 'OLD_SMALL_TBS' AND ROWNUM = 1;应无结果
注意:如果原表空间含物化视图日志、队列表、高级队列等特殊对象,需单独处理,不能仅靠 MOVE/REBUILD。
online redefinition 能否绕过停机?
可以,但只适用于单个表,且不改变表空间类型本身。用 DBMS_REDEFINITION 能在线把一张表从 smallfile 表空间搬到 bigfile 表空间,但无法批量、自动处理整个表空间的所有对象(比如序列、同义词、PL/SQL 包体不会被重定义)。所以它适合关键业务表,不适合整库表空间级迁移。
典型限制包括:
-
DBMS_REDEFINITION.START_REDEF_TABLE要求源表有主键或唯一约束 - 不迁移依赖对象(如触发器、授权、统计信息需手动同步)
- 中间表必须建在目标 bigfile 表空间里,否则失败
容易忽略的细节
真正卡住迁移的往往不是 SQL 语句,而是权限、状态和隐式依赖:
- 执行
MOVE前,确保用户有ALTER ANY TABLE或对象级ALTER权限;否则报ORA-01031: insufficient privileges - 表含
ENABLE ROW MOVEMENT才能支持MOVE(尤其分区表),否则报ORA-14102 - 迁移前检查
dba_tablespaces的status,若为READ ONLY,先ALTER TABLESPACE ... READ WRITE - 临时段、排序段、LOB index 等隐式对象不会随表自动迁移,需单独确认是否还在原表空间:
SELECT segment_type FROM dba_segments WHERE tablespace_name = 'OLD_SMALL_TBS' AND segment_type LIKE '%LOB%';
最后一步不是 DROP 原表空间,而是先 DROP TABLESPACE old_small_tbs INCLUDING CONTENTS AND DATAFILES —— 忘了 AND DATAFILES 就会留下磁盘文件。











