查表空间使用率不能只看DBA_FREE_SPACE,因其仅记录含空闲块的段,已满文件(无空闲extent)不出现,导致使用率误算偏低或为0;需联查DBA_DATA_FILES与DBA_FREE_SPACE,用TABLESPACE_NAME+FILE_ID精确关联,并对空文件用NVL补0。
查表空间使用率为什么不能只看 DBA_FREE_SPACE
因为 dba_free_space 只记录「当前有空闲块的段」,如果某个数据文件完全被占用(比如只剩一个未分配的 extent),它就不出现在这张表里;而 dba_data_files 记录的是所有数据文件的总大小。只查前者会漏掉“已满但没被标记为 free”的文件,导致使用率算低甚至为 0。
DBA_DATA_FILES 和 DBA_FREE_SPACE 怎么安全关联
必须用 TABLESPACE_NAME + FILE_ID 关联,不能只靠表空间名——同一表空间可能有多个文件,且 FILE_ID 是唯一物理标识。注意:DBA_FREE_SPACE.FILE_ID 和 DBA_DATA_FILES.FILE_ID 是对齐的,但 RELATIVE_FNO 不可替代。
- 先按
TABLESPACE_NAME分组汇总BYTES,再用FILE_ID精确匹配空闲块归属 - 对空文件(
DBA_FREE_SPACE中无记录)要补 0,否则SUM(f.bytes)会变成 NULL - 别用
LEFT JOIN后直接SUM(f.bytes)—— 没空闲块时整行消失,得改用子查询或NVL处理
一行能跑的实用 SQL(Oracle 11g+)
这个写法绕开了外连接陷阱,兼容空文件、自动归零、单位统一为 MB:
SELECT d.tablespace_name,
ROUND(SUM(d.bytes) / 1024 / 1024) AS total_mb,
ROUND(NVL(SUM(f.bytes), 0) / 1024 / 1024) AS free_mb,
ROUND((SUM(d.bytes) - NVL(SUM(f.bytes), 0)) / 1024 / 1024) AS used_mb,
ROUND((SUM(d.bytes) - NVL(SUM(f.bytes), 0)) / SUM(d.bytes) * 100, 2) AS pct_used
FROM dba_data_files d
LEFT JOIN dba_free_space f
ON d.tablespace_name = f.tablespace_name AND d.file_id = f.file_id
GROUP BY d.tablespace_name
ORDER BY pct_used DESC;容易被忽略的权限和一致性问题
执行前确认当前用户有 SELECT_CATALOG_ROLE 或直接授予 SELECT 权限在 DBA_DATA_FILES 和 DBA_FREE_SPACE 上;否则查不到数据或报 ORA-00942: table or view does not exist。
- 查询结果反映的是 SCN 一致性的快照,但
DBA_FREE_SPACE可能滞后几秒(尤其高并发 DML 场景) - 如果表空间是
UNDO或TEMP类型,DBA_FREE_SPACE不包含临时段空闲信息,得另查V$TEMP_SPACE_HEADER - 自动扩展(
AUTOEXTENSIBLE = YES)的文件,DBA_DATA_FILES.BYTES是当前已分配大小,不是最大值 —— 别把它当容量上限用
实际跑起来最常卡在权限和空文件处理上,尤其是刚建完表空间还没写入数据时,DBA_FREE_SPACE 是空的,但 DBA_DATA_FILES 已存在,这时候不加 NVL 就会丢行。

















