在Oracle 19c中,ALTER TABLE ... SHRINK SPACE CASCADE是最常用、最安全且能兼顾索引的高水位线回收方式;它支持在线分阶段执行、索引自动维护、可级联收缩依赖索引,但必须提前启用行移动,且不适用于含LONG列或CACHE+LOGGING的LOB表。

在 Oracle 19c 中,ALTER TABLE ... SHRINK SPACE CASCADE 是唯一能在线、保索引、分阶段执行且生产环境验证过的安全收缩方式;但必须提前启用行移动,且不能用于含 LONG 列或 LOB 段配置为 CACHE LOGGING 的表。
为什么 SHRINK SPACE 是首选而不是 MOVE 或 TRUNCATE
MOVE 会全程锁表,索引全部失效需手动重建,且不支持并行;TRUNCATE 只适用于清空全表,无法保留数据。而 SHRINK SPACE 在 19c 中已成熟支持:COMPACT 阶段只锁被移动的行(RX 锁),SHRINK SPACE 阶段仅需短暂 SX 表级锁;索引自动维护,加 CASCADE 可一并处理依赖索引。
常见错误现象:ORA-10636: row movement is not enabled —— 忘记执行 ENABLE ROW MOVEMENT;ORA-10655: Segment can be shrunk —— 表示段结构允许收缩,可放心执行。
使用场景包括:日志归档后批量 DELETE、统计信息准确、无未提交事务。若业务高峰不允许停写,可先运行 SHRINK SPACE COMPACT 整理碎片,再择机执行 SHRINK SPACE 下推 HWM。
执行前必须验证的三件事
盲目 SHRINK 可能失败或无效,尤其当 HWM 后面根本没有空块时。不能只看 DBA_TABLES.BLOCKS,必须用 DBMS_SPACE.SPACE_USAGE 查真实空间分布:
- 先确保统计信息最新:
EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA_NAME', 'TABLE_NAME'); - 检查回收站是否清空:
PURGE RECYCLEBIN;(否则已删对象仍占空间) - 确认表不含
LONG类型列,且所有LOB段未配置为CACHE LOGGING(该组合触发ORA-10637)
SHRINK 后为什么 RESIZE 还是报 ORA-03297
RESIZE 只能截断数据文件末尾的空块,前提是整个文件中最高 HWM ≤ 目标尺寸。而一个数据文件常混存多个段(表、索引、LOB、系统基表等)。只要任一对象的 HWM 超出目标值,RESIZE 就会失败。
查全文件最高 HWM(单位字节):SELECT MAX(block_id + blocks) * (SELECT value FROM v$parameter WHERE name = 'db_block_size') FROM dba_extents WHERE file_id = X;
容易忽略的点:
- 大索引可能比主表更占空间,却不在你收缩的目标表里
- WRH$_ 系列 AWR 基表即使没数据,也可能因延迟清理残留 Extent
- UNDO 或 TEMP 文件不支持 SHRINK,只能迁移
收缩后务必关闭行移动(可选但推荐)
启用 ROW MOVEMENT 后,某些基于 ROWID 的触发器或应用逻辑可能受影响。虽然 19c 对其兼容性增强,但生产环境建议在收缩完成后显式关闭:ALTER TABLE table_name DISABLE ROW MOVEMENT;
这不是强制步骤,但属于“容易被忽略的稳定性细节”——尤其当你后续要启用闪回查询、物化视图日志或审计策略时,ROW MOVEMENT 可能引发隐式行为变化。


















