dba_free_space是实例级缓存视图,仅反映本地lru管理器最近刷新的空闲块信息,存在滞后与不一致;真实表空间使用率必须逐节点查询dba_data_files与dba_free_space后汇总计算,不可跨节点推断。

DBA_FREE_SPACE 是实例级缓存,不是实时全局视图
查出来的使用率不一致,根本原因不是数据分布问题,而是 DBA_FREE_SPACE 本身只反映当前实例最近一次刷新的空闲块信息。它背后依赖本地 LRU 管理器定期扫描 buffer cache 中的 free list,高并发 DML 后可能滞后几秒甚至更久。不同节点刷缓存节奏不同、负载不均、甚至某节点刚重启过,都会导致 DBA_FREE_SPACE 返回结果差异明显。
- 不能用一个节点查出的
DBA_FREE_SPACE推断整个 RAC 集群的空间水位 -
DBA_DATA_FILES和DBA_TABLESPACES才是真正全局一致的——它们读的是数据字典基表,物理文件路径、大小、状态所有节点看到的都一样 - 真实空间压力要看
v$sort_segment(TEMP)、v$undostat(UNDO)、或直接算dba_data_files.bytes - dba_free_space.bytes每节点分别执行
TEMP 和 UNDO 表空间的“使用率”本质不同
TEMP 表空间的使用率在各节点天然就可能差很多,因为排序段(v$sort_segment)是实例私有资源:同一个 SQL 在节点1做大排序,在节点2可能走索引或小结果集,完全不碰 TEMP。UNDO 表空间虽共享,但长事务绑定到具体实例,v$transaction 中的 used_ublk 和 start_time 必须逐节点检查——某个节点卡着一个 2 小时未提交的事务,就会把 UNDO 表空间撑到 95%,其他节点却显示才 30%。
- 查 TEMP 使用:在每个节点运行
SELECT tablespace_name, used_blocks * 8 / 1024 AS gb_used FROM v$sort_segment; - 查 UNDO 压力:先看
SELECT MAX(expstealcount) FROM v$undostat;,>0 就说明已在抢块,此时调undo_retention无效 - RAC 中不存在“全局 TEMP 使用率”,只有“各节点当前排序负载”
查询脚本没适配 RAC,结果自然不可比
很多网上流传的“一行查表空间使用率”脚本,本质是 dba_free_space 左连接 dba_data_files。但若某节点上某个数据文件还没被访问过,dba_free_space 里压根没对应 file_id 的记录,LEFT JOIN 后 free_bytes 就是 NULL,算出来使用率直接变成 100%——这不是真满了,是视图没覆盖到。
- 安全写法必须显式 COALESCE 或 NVL 处理 free_bytes,例如:
SUM(NVL(free_bytes, 0)) - 脚本里别用
dba_free_space直接 GROUP BY,要先按file_id聚合,再 JOIN,否则跨文件统计会错 - 生产环境建议用带
ALTER SYSTEM CHECKPOINT前置的版本,强制刷一次脏块和空闲块映射,减少缓存偏差
真正要盯的不是“使用率数字”,而是增长趋势和瓶颈点
两个节点显示 85% 和 92%,未必代表后者更危险。关键看:这个 92% 是刚涨上去的(比如 10 分钟内从 70% 到 92%),还是稳定维持一整天;背后是不是有 gc cr block busy 等待事件拖慢了空间回收;或者某个节点正在跑大数据量 ETL,临时占满 TEMP 后又释放——这些动态行为,静态快照根本反映不出来。
- 用 AWR 报告对比两节点的
Tablespace IO和Buffer Pool Statistics,看物理读/写是否严重倾斜 - 查
v$sysstat中db block changes和physical writes,确认写热点是否集中在某节点 - 如果只是短期 spike,优先查应用连接路由(SCAN VIP / service preferred instance),避免盲目扩容











