物理空闲率=未分配空间/数据文件总大小,反映操作系统视角的真空闲;逻辑空闲率=(FS1–FS4字节)/段已分配大小,反映块内填充密度;二者统计维度不同,不可叠加。

物理空闲率 = dba_free_space.bytes / 表空间总大小
这是操作系统视角的“真·空闲”,只看数据文件里哪些块还没被任何段(表、索引、LOB)占用。它不关心块内部有没有碎片,也不管高水位线(HWM)以下那些已分配但实际没填满的块——哪怕一个块只存了1行,只要它属于某个段,就不算在这里。
关键点:
-
dba_free_space统计的是未分配给任何 segment 的空闲区(extent),单位是字节 - 表空间总大小 =
sum(bytes)fromdba_data_files(注意排除临时文件) - 如果表空间启用了 autoextend,
maxbytes不能直接当总大小用;物理空闲率只反映当前已分配文件空间的利用率 - 常见错误:把
dba_free_space和dba_segments混着加减——它们统计维度不同,强行相减会漏掉 unformatted blocks 和 HWM 上方空间
逻辑空闲率 ≈ (FS1_bytes + FS2_bytes + FS3_bytes + FS4_bytes) / 段已分配总大小
这是 DBA 看“块有多空”的真实密度指标,来自 DBMS_SPACE.SPACE_USAGE。它扫描每个已分配数据块的头部,按空闲空间比例打标:FS1(0–25% 空闲)、FS2(25–50%)、FS3(50–75%)、FS4(75–100%)。这些块都属于某个 segment,但内部有空洞。
注意:
- 必须满足三个硬条件:
segment_owner/segment_name/segment_type完全匹配、调用用户有EXECUTEonDBMS_SPACE、表空间为 ASSM(AUTO)模式 - 返回的
fs1_blocks等值 ≠ 可插入新行数,只是物理块填充率快照;高并发 DML 后可能很快变化 - 它不包含
unformatted_blocks(已分配但未格式化的块)和 HWM 以上空闲块,所以不能和dba_free_space直接叠加 - 逻辑空闲率分母不是表空间大小,而是该 segment 当前已分配的块 ×
block_size
为什么两个空闲率永远对不上?
因为它们回答的是完全不同的问题:
- 物理空闲率问:“这片地还有多少平方米没划给任何人?”
- 逻辑空闲率问:“已经盖了楼的地块里,每栋楼平均还剩多少平米没装修?”
- 中间那块“划给了某栋楼、但楼还没建完(unformatted)”或“楼盖到一半停了、上面全是毛坯(HWM 以上)”的地,两个指标都不算
- 所以你常看到:物理空闲率 30%,但查大表的
SPACE_USAGE显示 FS1–FS4 加起来只占 segment 大小的 15%——剩下那 15% 就是 unformatted + HWM 上方空间,得靠DBMS_SPACE.UNUSED_SPACE单独捞
实操时该信哪个?
看你要解决什么问题:
- 磁盘快满了?盯
dba_free_space——它决定你还能不能继续 insert - 某张表查询越来越慢、怀疑有大量链式行或块碎片?跑
DBMS_SPACE.SPACE_USAGE看 FS1/FS2 是否异常高,再结合ANALYZE TABLE ... LIST CHAINED ROWS - 评估 shrink 表空间可行性?必须三者并查:
dba_free_space(外部空闲)、SPACE_USAGE(内部空洞)、UNUSED_SPACE(HWM 位置)——缺一不可
最易被忽略的是:ASSM 表空间下,dba_segments.blocks 不等于物理块数,它含 unformatted blocks;而 SPACE_USAGE 返回的块数又排除了它们。同一张表,三个视图/过程给出的“块数”可能差出 20%。别用脑子记,写脚本时每个来源都显式注释清楚统计口径。


















