必须先执行enable row movement,因为shrink space会变更rowid,而默认禁止行移动以防破坏rowid依赖逻辑;不启用会报ora-10636错误。

为什么必须先执行 enable row movement
Oracle 的 shrink space 操作会改变行的物理位置(rowid 变更),而默认情况下表禁止行移动,否则可能破坏基于 rowid 的逻辑(比如某些触发器、物化视图日志、旧版应用依赖)。不提前启用,直接运行 alter table T3 shrink space 会报错:ORA-10636: ROW MOVEMENT is not enabled。
启用后,所有引用该表的 PL/SQL 对象(存储过程、包、视图)会被置为 INVALID。这不是错误,而是 Oracle 的强制校验机制——它需要确保后续调用能正确解析新 rowid。
-
alter table T3 enable row movement是 DDL,立即生效,无需 commit - 执行后建议立刻运行
@?/rdbms/admin/utlrp.sql(或exec dbms_utility.compile_schema)重新编译失效对象 - 如果表上有基于 rowid 的触发器(
BEFORE/AFTER ROW ON T3 REFERENCING OLD AS o NEW AS n),需手动禁用:alter trigger trig_name disable
shrink space 和 shrink space compact 的关键区别
两者都依赖已启用的行移动,但锁级别和业务影响完全不同:
-
shrink space compact:只做数据重组(把高水位线右侧的行往左挪),加 RX 锁(行级共享锁),DML 不阻塞,耗时短,适合在线业务期执行 -
shrink space:在 compact 基础上再移动高水位线(HWM),释放空闲数据块,加 X 锁(排他锁),期间所有 INSERT/UPDATE/DELETE 被挂起,必须选维护窗口执行 -
shrink space cascade:等价于shrink space+ 同时收缩该表所有索引段,避免后续单独 shrink index
典型分步操作:alter table T3 shrink space compact → 等业务低峰 → alter table T3 shrink space cascade。
收缩失败的三个硬性前提检查
即使启用了行移动,shrink space 仍可能静默跳过或报错,必须确认以下三点全部满足:
- 表空间是本地管理(LMT):查
select extent_management from dba_tablespaces where tablespace_name = 'USERS',结果必须是LOCAL - 表空间启用 ASSM(自动段空间管理):同一查询中
segment_space_management必须为AUTO,不能是MANUAL - 表是堆表(heap table):排除 IOT、簇表、含 LONG 列、含基于提交的物化视图依赖的表;可用
select iot_type from dba_tables where table_name = 'T3'验证,返回NULL才安全
任一不满足,shrink space 会报 ORA-10635: Invalid segment or tablespace type 或无提示地不释放空间。
收缩后空间没变小?别急着重试
执行 shrink space 后,dba_segments.bytes 可能未立即下降,常见原因:
- 数据字典缓存延迟:刷新 shared pool(
alter system flush shared_pool)或等待几分钟再查 - 高水位线已降,但表空间文件本身没缩小:
shrink space只回收段内空间,不缩数据文件;要缩文件得用alter database datafile ... resize,且目标大小不能小于该文件中最大已分配块位置(select max(block_id) * block_size from dba_extents) - 表上存在未清理的 LOB 段:LOB 数据不在主段里,需单独 shrink:
alter table T3 modify lob (clob_col) (shrink space)
真正释放的空间,只体现在段级别(dba_segments),而不是文件系统层面——这是最容易被忽略的边界。











