不能,ALTER TABLE ... SHRINK SPACE 不支持单个分区;需用 ALTER TABLE ... SHRINK SPACE PARTITION,且仅限 11gR2+ 的 RANGE/LIST/INTERVAL 堆表,并要求启用行移动。
Oracle 分区表单个分区能用 ALTER TABLE ... SHRINK SPACE 吗?
不能直接对单个分区执行 alter table ... shrink space。这个语句只作用于整个表(或 iot),不支持 partition 关键字。想收缩某个分区,必须换用分区级命令。
ALTER TABLE ... SHRINK SPACE PARTITION 的真实行为
Oracle 11gR2 起才支持该语法,但仅限于 LIST、RANGE、INTERVAL 分区的堆表(非索引组织表),且要求表启用行移动(ENABLE ROW MOVEMENT)。它实际做三件事:整理碎片、回收空间、更新高水位线(HWM)——但不会自动释放到表空间,需后续 ALTER TABLESPACE ... COALESCE 或手动 ALTER DATABASE DATAFILE ... RESIZE。
- 必须先执行
ALTER TABLE t ENABLE ROW MOVEMENT,否则报错ORA-10636: row movement is not enabled - 分区名必须显式写出,不支持通配符或子查询
- 若分区上有本地索引(
LOCAL),收缩后索引会自动维护;全局索引(GLOBAL)则需重建或指定UPDATE GLOBAL INDEXES - 执行期间该分区被加
SS(sub-share)锁,DML 不阻塞,但 DDL 会被挂起
常见错误:ORA-10631 和收缩失败的典型原因
ORA-10631: SHRINK clause should not be specified for this object 是最常遇到的报错,根本原因是对象类型不支持——比如试图对索引组织表(IOT)、外部表、物化视图日志表、或者未启用行移动的分区表执行收缩。
- 检查是否是 IOT:
SELECT iot_type FROM user_tables WHERE table_name = 'T',返回IOT或IOT_OVERFLOW就不支持 - 确认行移动已开启:
SELECT row_movement FROM user_tables WHERE table_name = 'T',结果必须是ENABLED - 分区表若含 LOB 列,需额外验证 LOB 段是否也启用了
ENABLE STORAGE IN ROW,否则可能静默跳过 LOB 数据收缩 - 使用
DBMS_SPACE.SPACE_USAGE查 HWM 前后变化,别只看BYTES字段——UNFORMATTED_BLOCKS才反映真实可回收量
替代方案:当 SHRINK SPACE PARTITION 不可用时
如果环境是 10g、或表结构受限(如含 LONG、嵌套表)、或需要更精细控制空间回收节奏,就只能绕道。核心思路是“导出 → 截断 → 重载”,但必须避开全表锁和长事务风险。
- 用
CREATE TABLE t_new AS SELECT * FROM t PARTITION (p1) WHERE 1=0快速建空分区结构 - 交换分区:
ALTER TABLE t EXCHANGE PARTITION p1 WITH TABLE t_new(要求约束、索引等完全匹配) - 再对
t_new执行TRUNCATE TABLE t_new REUSE STORAGE,此时原分区数据已清空,空间立即释放 - 若需保留数据,改用
INSERT /*+ APPEND */ INTO t_new SELECT /*+ FULL(t) */ * FROM t PARTITION (p1)+ 交换,但注意归档模式下会产生大量 redo
真正麻烦的不是语法,而是收缩前后统计信息失效、本地索引状态异常、以及业务高峰期锁等待堆积——这些点不提前压测,上线就卡住。










