判断表空间是否真碎片化需看DBA_FREE_SPACE中空闲块的数量与大小分布,关键指标是最大连续空闲extent(MAX(BYTES))能否满足业务所需;若MIN_MB极小、FREE_EXTENTS远超理论值、LARGEST_CONTIGUOUS_MB远小于数据文件最大尺寸,则存在严重碎片。
直接看 dba_free_space 里的空闲块数量和大小分布,就能判断是否真碎片化——空闲总量大不等于能用,关键在“能不能凑出一个新段需要的连续 extent”。
查空闲块数量与大小频次分布
只看总空闲 MB 没意义,得知道这些空闲空间是不是被切成几十个几 KB 的碎块。执行这个查询能一眼看出分布异常:
SELECT TABLESPACE_NAME,
COUNT(*) AS "FREE_EXTENTS",
ROUND(MIN(BYTES)/1024/1024, 2) AS "MIN_MB",
ROUND(MAX(BYTES)/1024/1024, 2) AS "MAX_MB",
ROUND(AVG(BYTES)/1024/1024, 2) AS "AVG_MB",
ROUND(SUM(BYTES)/1024/1024, 2) AS "TOTAL_FREE_MB"
FROM DBA_FREE_SPACE
GROUP BY TABLESPACE_NAME
ORDER BY "TOTAL_FREE_MB" DESC;
- 如果
MIN_MB是0.06(64KB)、MAX_MB是256,且FREE_EXTENTS远大于TOTAL_FREE_MB / AVG_MB的理论值,说明存在大量小碎片 -
DBA_FREE_SPACE不包含 HWM 以上未格式化的空间,也不反映 ASSM 下的位图块状态,它只告诉你“当前已知的、可分配的空闲 extent” - 必须用 DBA 权限用户执行;普通用户只能查
USER_FREE_SPACE,且仅限默认表空间
识别单个数据文件内的空闲不连续性
表空间由多个数据文件组成,碎片可能集中在某几个文件里。按 FILE_ID 分组能定位具体瓶颈文件:
SELECT TABLESPACE_NAME, FILE_ID,
COUNT(*) AS "EXTENT_COUNT",
ROUND(SUM(BYTES)/1024/1024, 2) AS "FREE_MB",
ROUND(MIN(BYTES)/1024/1024, 2) AS "SMALLEST_MB",
ROUND(MAX(BYTES)/1024/1024, 2) AS "LARGEST_MB"
FROM DBA_FREE_SPACE
GROUP BY TABLESPACE_NAME, FILE_ID
ORDER BY "FREE_MB" DESC;
- 若某个
FILE_ID的EXTENT_COUNT高但FREE_MB低,大概率是该文件被反复 delete/insert 后留下大量小空洞 - 注意:自动扩展开启时,新分配的文件末尾可能全是连续大块,掩盖前面文件头的碎片问题
- ASSM 表空间下,
SEGMENT_SPACE_MANAGEMENT = 'AUTO',此时DBA_FREE_SPACE中的 extent 大小受位图管理策略影响,不一定等于你定义的 uniform size
对比理论最大可分配块与实际最大空闲块
真正影响对象扩容的是“当前能拿出的最大连续空闲 extent”。用这个查询快速抓出瓶颈:
SELECT TABLESPACE_NAME,
ROUND(MAX(BYTES)/1024/1024, 2) AS "LARGEST_CONTIGUOUS_MB",
(SELECT ROUND(MAX(bytes)/1024/1024, 2)
FROM dba_data_files d
WHERE d.tablespace_name = f.tablespace_name) AS "LARGEST_DATAFILE_MB"
FROM DBA_FREE_SPACE f
GROUP BY TABLESPACE_NAME
ORDER BY "LARGEST_CONTIGUOUS_MB";
- 如果
LARGEST_CONTIGUOUS_MB远小于LARGEST_DATAFILE_MB(比如后者是 2048MB,前者只有 8MB),说明即使文件很大,也因碎片无法支持大对象插入或索引重建 - 该值低于业务最大单次写入量(如分区表单个分区预估 500MB)时,就该考虑
ALTER TABLE ... MOVE或表空间重组 - 不要依赖
dba_segments的blocks字段反推空闲——它不含未格式化块,也不含回收站对象占的空间
碎片是否要处理,不取决于空闲总量,而取决于你的业务能否持续分配所需大小的 extent。哪怕空闲还有 2GB,只要最大连续块只有 64KB,CREATE INDEX 就可能报 ORA-01652。别只盯着百分比,盯住 MAX(BYTES) 和 COUNT(*) 的组合信号。


















