ALTER USER DEFAULT TABLESPACE 无法迁移现有表,必须逐个处理表、索引、LOB、分区、IOT溢出段等附属段,并在MOVE后立即REBUILD索引、收集统计信息,否则将导致ORA-01502、性能下降或执行计划劣化。

不能直接用 ALTER USER DEFAULT TABLESPACE 切换已有表的位置——它只影响后续新建对象,对现存表完全无效。必须逐个处理表及其所有附属段。
先确认哪些对象要动,别漏掉隐性依赖
表迁移不是只动 user_tables 里的记录。LOB、索引、分区、IOT 溢出段都各自独立占段,且默认不随表移动。漏掉任何一个,应用可能查不到数据、DML 报错或性能骤降。
- 查表本身:
SELECT table_name, tablespace_name FROM user_tables WHERE tablespace_name = 'OLD_TBS' - 查索引:
SELECT index_name, tablespace_name FROM user_indexes WHERE tablespace_name = 'OLD_TBS' - 查 LOB:
SELECT table_name, column_name, tablespace_name FROM user_lobs WHERE tablespace_name = 'OLD_TBS' - 查分区:
SELECT table_name, partition_name, tablespace_name FROM user_tab_partitions WHERE tablespace_name = 'OLD_TBS'
特别注意:user_lobs 中的 segment_name 和 tablespace_name 才是真实位置,别只看表名所在表空间就以为 LOB 也跟着走了。
MOVE 表 + REBUILD 索引必须分两步,顺序不能反
ALTER TABLE ... MOVE TABLESPACE 会把所有普通索引置为 UNUSABLE,但不会报错;查询带索引条件时可能直接抛 ORA-01502。必须在 MOVE 后立刻重建,不能等批量脚本跑完再统一处理。
- 生成 MOVE 语句时加保护:
SELECT 'ALTER TABLE ' || table_name || ' MOVE TABLESPACE NEW_TBS;' FROM user_tables WHERE tablespace_name = 'OLD_TBS' AND status = 'VALID' - 表名含大小写或特殊字符?用
'"' || table_name || '"'包裹,否则执行报ORA-00942 - 重建索引别只按
user_indexes跑——有些函数索引、位图索引可能没列在默认视图里,建议连dba_indexes一起查 - 重建命令末尾必须有分号,SQL*Plus 粘贴时缺分号会把下一行当续行,导致语法错误
LOB 和分区表不能“一锅端”,得拆开单独处理
含 LOB 字段的表,MOVE TABLESPACE 只动表段,LOBSEGMENT 和 LOBINDEX 仍钉在旧表空间。分区表整表 MOVE 会直接报 ORA-14511,必须按分区操作。
- LOB 迁移语句示例:
ALTER TABLE "MyTable" MOVE LOB("content") STORE AS (TABLESPACE NEW_TBS) - 分区迁移语句示例:
ALTER TABLE "Sales" MOVE PARTITION "P_2024_Q1" TABLESPACE NEW_TBS - 如果表是 IOT,还得额外补一句:
ALTER TABLE "MyIotTable" MOVE OVERFLOW TABLESPACE NEW_TBS - LOB 分区(如 SECUREFILE)不支持
MOVE PARTITION ONLINE,只能先主表迁移,再单独处理 LOB 分区
大表迁移后必须手动收集统计信息
MOVE 不更新 DBA_TAB_STATISTICS,优化器仍按旧数据量估算,可能导致执行计划劣化——比如该走索引却选了全表扫描。这不是“可能”,而是必然发生。
- 迁移完成后立即执行:
EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCHEMA_NAME', tabname => 'TABLE_NAME') - 别依赖自动统计信息收集任务,它可能几小时后才触发,中间窗口就是故障高发期
- 如果表有直方图或列级统计,记得加
method_opt参数显式指定,否则默认不收集
真正难的不是写出那几条 ALTER 语句,而是确认每个附属段是否真的落到了新位置、每个索引是否可用了、统计信息是否已生效——这些没法靠脚本自动验证,得人工查 dba_segments 和 user_indexes.status。


















