DBA_FREE_SPACE的“空闲总量”准确,但SUM(BYTES)不反映碎片程度,因其仅统计连续空闲EXTENT;真正需关注的是BLOCK_ID与BLOCKS组合判断物理连续性,并验证能否满足NEXT_EXTENT分配需求。
DBA_FREE_SPACE里查到的“空闲总量”为什么不准?
因为dba_free_space只记录**连续空闲extent**,不是字节池快照。哪怕表空间只剩10mb空闲,若被切成200个50kb碎片,视图就会返回200行——sum(bytes)加起来仍是10mb,但最大单块可能只有50kb。误把行数多当成“碎片严重”,或只看sum(bytes)就以为空间充足,是常见错觉。
怎么看出哪些空闲块其实是相邻的?
BLOCK_ID和BLOCKS才是物理连续性的唯一依据,BYTES只是换算值,受DB_BLOCK_SIZE影响还可能四舍五入失真。必须用这两个字段做真实合并判断:
- 先查块大小:
SELECT VALUE FROM V$PARAMETER WHERE NAME = 'db_block_size' - 找相邻对:
SELECT t1.BLOCK_ID, t1.BLOCKS, t2.BLOCKS FROM DBA_FREE_SPACE t1 JOIN DBA_FREE_SPACE t2 ON t1.TABLESPACE_NAME = t2.TABLESPACE_NAME AND t1.FILE_ID = t2.FILE_ID AND t1.BLOCK_ID + t1.BLOCKS = t2.BLOCK_ID - 过滤文件头干扰:
WHERE t1.BLOCK_ID > 10(跳过前几个保留块)
如何快速判断是否真影响业务?
碎片率数字本身没用,关键看能否满足下一次EXTENT申请。实操分三步:
- 查主流对象的
NEXT_EXTENT:SELECT DISTINCT NEXT_EXTENT FROM DBA_SEGMENTS WHERE TABLESPACE_NAME = 'USERS',重点关注高频值(如1048576字节即1MB) - 反查能否分配:
SELECT COUNT(*) FROM DBA_FREE_SPACE WHERE TABLESPACE_NAME = 'USERS' AND BYTES >= 1048576,返回0就说明卡住了 - 排除ASSM干扰:如果是
EXTENT MANAGEMENT LOCAL AUTOALLOCATE,BYTES 的记录占多数属正常,别一看到<code>COUNT(*) > 100就panic
为什么ORDER BY BLOCK_ID后肉眼扫几行很有效?
刚DEALLOCATE出来的空闲块往往物理连续,BLOCK_ID会呈等差序列(比如1000、1008、1024)。按TABLESPACE_NAME, FILE_ID, BLOCK_ID排序后,连续几行BLOCK_ID差值等于DB_BLOCK_SIZE对应块数,基本就能确认是同一段——这种直观判断比写复杂窗口函数更快,也更不容易漏掉跨文件但逻辑连续的异常情况。


















