dbms_space.space_usage仅查assm下指定段的块级空闲分布(fs1–fs4、full、unformatted),不查lob/索引/分区子段、hwm以上空间及mssm表空间;需dba权限、assm表空间、准确段类型。

DBMS_SPACE.SPACE_USAGE 能查什么、不能查什么
这个过程只返回单个段(比如一张表)的块级空间分布,不涉及LOB段、索引段或分区子段——哪怕它们和这张表强关联,也得单独调用。常见误判是:查了 DBMS_SPACE.SPACE_USAGE 显示 full_blocks 很高,就以为没碎片,结果发现磁盘空间还在涨,根源是 CLOB 字段对应的 LOBSEGMENT 没查。
它也不反映高水位线(HWM)以上的“空闲但不可用”空间。那些空间在 DBA_SEGMENTS.BYTES 里算进去了,但在 SPACE_USAGE 输出中完全不出现。
- 能查:ASSM 表空间下某张表/索引段内各空闲程度的数据块数量(
FS1_BLOCKS到FS4_BLOCKS)、未格式化块(UNFORMATTED_BLOCKS)、已满块(FULL_BLOCKS) - 不能查:
SECUREFILE LOB(得用另一个重载)、MSSM 表空间(会报 ORA-10614)、HWM 以上空间、附属段(LOB/INDEX)
执行前必须确认的三件事
漏掉任意一项都会导致报错或结果失真:
- 当前用户要有
DBA角色或对目标段的SELECT权限;普通用户查USER_FREE_SPACE只能看到默认表空间,且无法调用DBMS_SPACE.SPACE_USAGE - 目标段所在表空间必须是
AUTOMATIC SEGMENT SPACE MANAGEMENT (ASSM);查DBA_TABLESPACES.SEGMENT_SPACE_MANAGEMENT确认值为AUTO - 段类型必须拼写准确:
'TABLE'、'INDEX'、'TABLE PARTITION'—— 少引号、大小写错、多空格全都会触发 ORA-06550 或 ORA-00904
怎么看输出里的碎片信号
FS1_BLOCKS(0–25% 空闲)和 FS2_BLOCKS(25–50% 空闲)偏高,通常说明有行迁移或更新膨胀;FS3_BLOCKS(50–75% 空闲)和 FS4_BLOCKS(75–100% 空闲)占比大,更可能是删除后未收缩,属于可回收型碎片。
真正危险的信号是:UNFORMATTED_BLOCKS 显著大于 0,且 FULL_BLOCKS 占比低于 60%,同时 FS1_BLOCKS + FS2_BLOCKS 总和远小于 FULL_BLOCKS。这表示大量块处于“半满难用”状态——既不够空去插入新行,又不够满到能被高效扫描。
- 安全阈值参考:若
(FS1_BLOCKS + FS2_BLOCKS) / (FULL_BLOCKS + FS1_BLOCKS + FS2_BLOCKS + FS3_BLOCKS + FS4_BLOCKS) > 0.35,建议优先检查是否发生过批量UPDATE导致链式行(CHAINED ROWS) - 注意
FS4_BLOCKS高 ≠ 碎片严重;它可能只是刚DELETE完还没SHRINK,这类空间可通过ALTER TABLE ... SHRINK SPACE COMPACT快速回收
别跳过的兼容性细节
Oracle 12c 及以后版本对 DBMS_SPACE.SPACE_USAGE 增加了参数校验逻辑:如果传入的 segment_name 是分区表但没指定 partition_name,过程不会报错,而是静默返回整个段的聚合值——但这会掩盖某个特定分区的严重碎片。必须显式传参才能定位到分区级问题。
另外,DBMS_SPACE.SPACE_USAGE 在查询全局临时表(GLOBAL TEMPORARY TABLE)时行为异常:它可能返回 0 块统计,即使该 GTT 当前有活跃数据。这不是 bug,而是设计使然——临时段空间由会话私有管理,不在共享段视图中暴露。
最常被忽略的一点:DBMS_SPACE.SPACE_USAGE 返回的是快照值,不加锁也不阻塞 DML。但如果在高并发更新期间执行,看到的 FSx_BLOCKS 分布可能和实际业务负载下的真实分布偏差较大——建议在低峰期运行,或结合 V$SEGSTAT 中的 space_used 和 space_allocated 动态指标交叉验证。











