查DBA_FREE_SPACE不能直接反映碎片率,因其仅返回空闲extent原始记录而未区分大小及可分配性;应使用DBMS_SPACE.FREE_SPACE按块级分档(FS1~FS4+FULL)分析真实可用性。

查 DBA_FREE_SPACE 不能直接反映“碎片率”
很多人一上来就跑 SELECT tablespace_name, SUM(bytes) FROM dba_free_space GROUP BY tablespace_name,以为总空闲字节数就是可用空间——这是错的。Oracle 的空闲空间由多个不连续的 extent 组成,dba_free_space 返回的是所有空闲 extent 的原始记录,但没告诉你这些 extent 多大、是否能被新段分配使用。尤其当表空间启用了 AUTOALLOCATE(如 SYSTEM、SYSAUX),extent 大小动态变化(64K→1M→64M),小碎片堆满却无法容纳一个 1MB 的新表,实际“可用性”远低于统计值。
用 DBMS_SPACE.FREE_SPACE 获取真实可分配块分布
要量化碎片,必须落到块级,并区分不同大小的空闲区间。Oracle 提供了官方过程 DBMS_SPACE.FREE_SPACE,它按空闲 extent 的块数分档(FS1~FS4 和 FULL),这才是判断碎片程度的依据:
-
FS1: 空闲块数 ∈ [0, 24] —— 极小碎片,基本无用 -
FS2: ∈ [25, 49] —— 小碎片,仅适合极小对象 -
FS3: ∈ [50, 74] —— 中等碎片 -
FS4: ∈ [75, 100] —— 接近完整块,较实用 -
FULL: 完全空闲的数据块(未格式化或刚释放)
执行前需注意:
- 必须以
sys或具有EXECUTE ON DBMS_SPACE权限的用户运行 - 只适用于本地管理(LMT)、自动段空间管理(ASSM)的永久表空间;
TEMP和UNDO不支持 - 需提前创建存储过程包装或用匿名块调用,例如:
DECLARE
l_unformatted_blocks NUMBER;
l_unformatted_bytes NUMBER;
l_fs1_blocks NUMBER; l_fs1_bytes NUMBER;
l_fs2_blocks NUMBER; l_fs2_bytes NUMBER;
l_fs3_blocks NUMBER; l_fs3_bytes NUMBER;
l_fs4_blocks NUMBER; l_fs4_bytes NUMBER;
l_full_blocks NUMBER; l_full_bytes NUMBER;
BEGIN
DBMS_SPACE.FREE_SPACE(
segment_owner => NULL,
segment_name => NULL,
segment_type => 'TABLESPACE',
tablespace_name => 'USERS',
free_blks => l_unformatted_blocks,
free_bytes => l_unformatted_bytes,
fs1_blks => l_fs1_blocks,
fs1_bytes => l_fs1_bytes,
fs2_blks => l_fs2_blocks,
fs2_bytes => l_fs2_bytes,
fs3_blks => l_fs3_blocks,
fs3_bytes => l_fs3_bytes,
fs4_blks => l_fs4_blocks,
fs4_bytes => l_fs4_bytes,
full_blks => l_full_blocks,
full_bytes => l_full_bytes
);
DBMS_OUTPUT.PUT_LINE('FS1 blocks: ' || l_fs1_blocks);
DBMS_OUTPUT.PUT_LINE('FS4 + FULL blocks: ' || (l_fs4_blocks + l_full_blocks));
END;
碎片率不是百分比,而是“有效空闲块占比”
别硬算“碎片率 = FS1 块数 / 总空闲块数”。真正影响业务的是:当前最常申请的 segment(比如普通表、索引)需要多少初始 extent?如果多数对象默认请求 8 个块(64KB),而你表空间里 90% 的空闲 extent 都是 FS1(≤24 块),那即使总空闲空间还有 5GB,也可能报 ORA-01653。
- 查当前表空间的 extent 管理方式:
SELECT extent_management, allocation_type FROM dba_tablespaces WHERE tablespace_name = 'USERS' - 若为
UNIFORM,确认 uniform size(如 1M = 128 块)→ 关注FS4和FULL是否 ≥ 128 块 - 若为
AUTOALLOCATE,重点看FS4+FULL占总空闲块的比例是否 ≥ 60%,否则视为高碎片风险
临时表空间和撤销表空间不适用此方法
DBMS_SPACE.FREE_SPACE 对 TEMP 表空间会报 ORA-10614,对 UNDO 则直接不支持。它们的空间管理机制完全不同:
-
TEMP碎片看v$sort_segment中used_extents与total_extents比值,再结合v$sort_usage查活跃排序占用 -
UNDO关键是undo_retention和db_block_size决定的保留需求,碎片意义弱,更应关注v$undostat的unxpstealcnt(非到期块被偷用次数)
真正难处理的是那些长期只增不删、又没开 ASSM 的老表空间——它们的碎片无法靠 SQL 直接量化,只能结合 DBMS_SPACE.SPACE_USAGE 查单个大表的高水位下空闲块分布,再外推判断。


















