需移动的表及当前表空间可通过SELECT table_name, tablespace_name FROM user_tables WHERE tablespace_name != 'NEW_TBS' AND tablespace_name NOT IN ('SYSTEM','SYSAUX','UNDO') AND status='VALID'查询;再用SELECT 'ALTER TABLE '||table_name||' MOVE TABLESPACE NEW_TBS;'生成语句,LOB字段须显式指定STORE AS,索引失效后需重建。
查出所有需要移动的表及其当前表空间
批量移动表前,必须先确认哪些表要动、现在在哪——不能靠猜。用 dba_tables 或 user_tables 查是最稳妥的,注意权限:普通用户只能查自己的表,dba 才能查全库。
常用查询语句:
SELECT table_name, tablespace_name FROM user_tables WHERE tablespace_name != 'NEW_TBS';
如果目标是迁移非系统表且避开 SYSTEM、SYSAUX 等关键表空间,可加过滤:
AND tablespace_name NOT IN ('SYSTEM', 'SYSAUX', 'UNDO')-
AND status = 'VALID'(排除无效对象)
生成 ALTER TABLE ... MOVE TABLESPACE 语句
ALTER TABLE 是唯一能在线移动堆表(非分区表)的方式,但要注意:它会重建表段,不保留原物理顺序,且会失效索引——这点极易被忽略。
生成脚本示例(SQL*Plus 或 SQL Developer 中执行):
SELECT 'ALTER TABLE ' || table_name || ' MOVE TABLESPACE NEW_TBS;' FROM user_tables WHERE tablespace_name != 'NEW_TBS';
关键点:
- 语句末尾必须有分号,否则导出后执行报错
- 表名含大小写或特殊字符时,需用双引号包裹,例如:
"MyTable" - 如果表有 LOB 字段,仅
MOVE TABLESPACE不够,还需额外处理LOB存储子句
处理 LOB 字段和索引失效问题
带 LOB 的表移动后,LOB 段默认不会跟着走,仍留在原表空间,导致空间没真正释放。必须显式指定 LOB 子句:
ALTER TABLE t1 MOVE TABLESPACE NEW_TBS LOB (clob_col) STORE AS (TABLESPACE NEW_TBS);
索引则全部失效(STATUS = 'UNUSABLE'),需重建:
- 批量生成索引重建语句:
SELECT 'ALTER INDEX ' || index_name || ' REBUILD;' FROM user_indexes WHERE status = 'UNUSABLE'; - 或一步到位:在
MOVE后加UPDATE INDEXES(Oracle 12c+ 支持,但仅对某些索引类型有效) - 分区表不支持
MOVE整体操作,得用ALTER TABLE ... MOVE PARTITION
执行前检查与风险控制
直接跑生成的脚本风险很高,尤其在生产环境。务必提前验证:
- 目标表空间是否有足够空闲空间?用
dba_free_space查 - 表是否被锁?
SELECT * FROM v$locked_object WHERE object_id IN (SELECT object_id FROM dba_objects WHERE object_name = 'XXX'); - 避免在业务高峰执行;大表移动可能持续数分钟,期间 DML 可能阻塞
- 建议先导出语句到文件,人工 review 一遍再执行,别管道直连跑
最常被跳过的一步:没检查外键依赖。如果表被其他表的外键引用,MOVE 本身不影响约束,但若涉及主键索引重建失败,会导致约束异常。











