真正要管住的是段级空间利用率,而非磁盘组总容量;需通过DBA_SEGMENTS和DBA_EXTENTS分析真实使用率与碎片,收缩前确认行移动启用、无受限索引、表空间为本地自动管理,ASM下还需手动RESIZE数据文件释放空间。
直接扩容数据文件不是万能解法,尤其当表空间里存在大量碎片化段(比如频繁 delete/insert 的历史表、归档分区),光加文件只会让空间浪费更隐蔽。真正要管住的是段级空间利用率,而不是磁盘组总容量。
查清哪些段在吃掉空间但实际没用
先别急着 ALTER TABLESPACE ... ADD DATAFILE,用 DBA_SEGMENTS 和 DBA_EXTENTS 对比看真实使用率。常见错误是只看 DBA_FREE_SPACE 以为还有空,其实高水位线(HWM)卡在中间,下面全是“看不见的空”。
-
SELECT segment_name, segment_type, bytes/1024/1024 "MB", blocks, extents FROM dba_segments WHERE tablespace_name = 'ODS' ORDER BY bytes DESC—— 找出前 10 大段 -
SELECT segment_name, ROUND((blocks * 8192 - NVL(bytes_used,0)) / 1024 / 1024, 2) "WASTED_MB" FROM dba_segments s LEFT JOIN v$segment_statistics ss ON s.segment_name = ss.obj# AND ss.statistic# = 36 WHERE s.tablespace_name = 'ODS' AND ss.value > 0—— 粗略估算浪费空间(需开启统计) - 注意:
v$segment_statistics中 statistic# = 36 是 “space used”,但该视图默认不实时刷新,生产环境建议结合DBMS_SPACE.SPACE_USAGE过程做精确分析
收缩段前必须确认的三件事
执行 ALTER TABLE ... SHRINK SPACE 前,如果漏掉任一条件,操作会失败或锁表时间远超预期。
- 表必须启用行移动:
ALTER TABLE schema.table_name ENABLE ROW MOVEMENT—— 否则报错ORA-10636: row movement is not enabled - 不能有基于函数的索引、域索引、IOT 的映射表,否则
SHRINK SPACE COMPACT会跳过这些对象 - 确保所在表空间是本地管理(
EXTENT MANAGEMENT LOCAL)且段空间自动管理(SEGMENT SPACE MANAGEMENT AUTO),查DBA_TABLESPACES的allocation_type和segment_space_management字段
ASM 下收缩后空间不会自动返还给磁盘组
这是最容易被忽略的点:段收缩只是把 HWM 往下拉,释放的空间回到表空间的空闲链表里,但 ASM 磁盘组的 FREE_MB 不会变。你得手动触发 ALTER DATABASE DATAFILE ... RESIZE 或迁移数据文件才能真正腾出 ASM 空间。
- 先查数据文件当前大小和自动扩展状态:
SELECT file_name, bytes/1024/1024 "CURR_MB", autoextensible, maxbytes/1024/1024 "MAX_MB" FROM dba_data_files WHERE tablespace_name = 'ODS' - 若文件未启
AUTOEXTEND,收缩后可安全RESIZE;若已启用,先ALTER DATABASE DATAFILE '+DATA/pgjt/datafile/ods.539.784460919' AUTOEXTEND OFF,再RESIZE到合理值(如当前已用空间 + 10% 缓冲) - 注意:ASM 文件不支持直接
RESIZE到任意小值,最小只能缩到该文件中最高块号对应的实际占用大小,低于该值会报ORA-1725
别名路径对空间管理没帮助,但影响后续维护
很多人喜欢给 ASM 数据文件起别名(比如 +DATA/PGJT/ODS02.dbf),觉得看着清楚。但它只是个指向,不影响空间分配逻辑,反而容易掩盖问题:
- 用别名创建文件时,Oracle 仍按规则生成完全限定名(如
+DATA/pgjt/datafile/ods02.785.784460919),别名本身不参与空间计算 - 删除表空间时,别名不会自动清理,
ASMCMD里残留的别名可能误导你判断文件是否还被引用 - 查
v$datafile显示的是别名,但查v$asm_file显示的是真实文件名,两边对不上就容易误判“文件丢失”
真正要盯紧的,是 v$asm_diskgroup.FREE_MB 和 dba_segments.bytes 的差值,以及每个段的 blocks 与 extents 比值——比值越低,碎片越重,越值得优先收缩。


















