ALTER TABLESPACE SHRINK SPACE 不能释放磁盘空间,因其仅在表空间内重组空闲块、下移HWM,不改变数据文件物理大小;必须先收缩段(如表、索引)压低HWM,再用RESIZE缩小文件。

直接收缩表空间本身不能释放磁盘空间给操作系统,必须先收缩段(如表、索引),再用 ALTER DATABASE DATAFILE ... RESIZE 缩小数据文件;否则 ALTER TABLESPACE ... SHRINK SPACE 只是整理内部空闲块,不减少文件大小。
为什么 ALTER TABLESPACE SHRINK SPACE 不释放磁盘空间
这个命令只在表空间内部重新组织空闲区(free extent),把高水位线(HWM)后的空块往前挪,并不修改底层数据文件的物理尺寸。它作用于 ASSM 段管理逻辑层,和操作系统文件系统无关。
-
ALTER TABLESPACE tbs_name SHRINK SPACE成功后,dba_free_space中空闲块总和可能变大,但dba_data_files.bytes完全不变 - 常见误判:看到
dba_free_space有几百 GB 空闲,就以为能直接 shrink 表空间 → 实际上这些空闲块可能分散、不连续,无法被SHRINK SPACE合并成一个可回收的大块 - 真正能缩小数据文件的前提是:HWM 必须足够低,且 HWM 到文件末尾之间全是未格式化的(unformatted)空间 —— 这只能靠先收缩表/索引段来达成
收缩表段是找回磁盘空间的必经步骤
只有把表、索引、LOB 等段的高水位线压下去,才能让数据文件末尾出现连续的未使用空间,后续 RESIZE 才有效。跳过这步直接对表空间执行 SHRINK SPACE,大概率静默失败或无任何效果。
- 先确认表启用行移动:
ALTER TABLE t ENABLE ROW MOVEMENT,否则SHRINK SPACE报ORA-10636 - 检查表空间段管理必须为
AUTO:SELECT segment_space_management FROM dba_tablespaces WHERE tablespace_name = 'TBS_NAME'→ 必须返回'AUTO' - 对大表优先用
SHRINK SPACE COMPACT(加 RX 锁,不影响 DML),再用SHRINK SPACE(瞬时 SX 锁,释放空间) - 分区表要单独处理每个分区:
ALTER TABLE t MODIFY PARTITION p202406 SHRINK SPACE CASCADE - SECUREFILE LOB 必须显式收缩:
ALTER TABLE t MODIFY LOB (col_lob) (SHRINK SPACE);BASICFILE LOB 在 19c 不支持 shrink,只能MOVE PARTITION+REBUILD INDEX
RESIZE 数据文件前必须验证空闲空间位置
即使 dba_free_space 显示大量空闲,若它们位于文件中间而非末尾,RESIZE 仍会报 ORA-03297(文件包含超出请求尺寸的数据)。必须确认“可安全截断”的最大字节数。
- 查当前文件末尾可用收缩量:
SELECT file_id, bytes, blocks, user_blocks FROM dba_data_files WHERE tablespace_name = 'TBS_NAME' - 查 HWM 位置:
SELECT block_id, blocks, bytes FROM dba_extents WHERE file_id = &file_id ORDER BY block_id DESC,取最大block_id + blocks对应的块号,乘以db_block_size得到 HWM 字节位置 - 安全
RESIZE值必须 ≤ HWM 字节位置;建议留 1–2 MB 余量,例如:ALTER DATABASE DATAFILE '/path/to/file.dbf' RESIZE 12345M - 执行前务必清空回收站:
PURGE RECYCLEBIN,否则已删对象仍占空间,HWM 压不下去
收缩后必须手动收集统计信息
所有 SHRINK 操作完成后,DBA_TABLES.BLOCKS 和 NUM_ROWS 不会自动更新,优化器仍按旧值估算执行计划,极易引发性能倒退。
- 立即执行:
EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA_NAME', 'TABLE_NAME') - 若表有多个分区,加
cascade => TRUE参数确保索引统计也更新 - 别依赖自动统计任务——它可能延迟数小时,而业务查询已在用错误基数跑计划
- 特别注意:LOB 段收缩后,对应表的统计信息也要重收集,否则 CLOB/BLOB 列访问可能走错路径
真正卡住磁盘空间回收的,从来不是命令没敲对,而是 HWM 没压下去、空闲块不连续、回收站没清空、统计信息没更新——这四点漏掉任一,RESIZE 就会失败,或者收缩完性能反而更差。











