4. 表空间与数据文件容量分析
容量规划的第一步不是“加空间”,而是把当前空间账算清楚。Oracle 的空间消耗分布在三类表空间上:永久表空间承载业务数据与索引,临时表空间承载排序、哈希连接、全局临时表等中间结果,UNDO 表空间保存回滚数据以支撑读一致性与事务回滚。三者的增长驱动因素、风险表现和处置手段完全不同,必须分开采集、分开判断,最后再合并成一张容量风险清单。
一、先建立统一的采集口径
分析前先固定口径,否则不同时间点的数据无法比较。建议统一使用 DBA_TABLESPACE_USAGE_METRICS 获取永久与 UNDO 表空间的使用率,用 DBA_TEMP_FREE_SPACE 获取临时表空间使用情况,用 DBA_DATA_FILES 与 DBA_TEMP_FILES 获取文件级容量与自动扩展配置。下面是一组可直接执行的采集语句:
-- 永久表空间与 UNDO:使用率、剩余可分配空间
SELECT tablespace_name,
ROUND(used_space * 8192 / 1024 / 1024, 1) AS used_mb,
ROUND(tablespace_size * 8192 / 1024 / 1024, 1) AS total_mb,
ROUND(used_percent, 2) AS used_pct
FROM dba_tablespace_usage_metrics
ORDER BY used_percent DESC;
-- 临时表空间:已用与空闲
SELECT tablespace_name,
ROUND(allocated_space / 1024 / 1024, 1) AS alloc_mb,
ROUND(free_space / 1024 / 1024, 1) AS free_mb
FROM dba_temp_free_space;
-- 文件级:自动扩展与上限
SELECT tablespace_name, file_name,
ROUND(bytes / 1024 / 1024, 1) AS cur_mb,
autoextensible,
ROUND(maxbytes / 1024 / 1024, 1) AS max_mb,
increment_by * 8192 / 1024 / 1024 AS next_mb
FROM dba_data_files
UNION ALL
SELECT tablespace_name, file_name,
ROUND(bytes / 1024 / 1024, 1),
autoextensible,
ROUND(maxbytes / 1024 / 1024, 1),
increment_by * 8192 / 1024 / 1024
FROM dba_temp_files;
注意 used_percent 的分母是“当前已分配并可用的空间”,不是文件上限。因此一个使用率 95% 但 autoextensible=YES 且 maxbytes 远大于当前 bytes 的表空间,风险等级要低于一个使用率 80% 但 autoextensible=NO 的表空间。这正是必须把使用率与自动扩展配置放在一起看的原因。
二、永久表空间:看增长斜率而非瞬时水位
永久表空间的风险来自“持续增长 + 无法扩展”。判断增长趋势的实用做法是每日定时采样并留存历史,例如建立一张监控表,每天凌晨插入一次快照,积累两周后即可计算日均增量:
CREATE TABLE tbs_hist (
snap_date DATE,
tbs_name VARCHAR2(30),
used_mb NUMBER,
total_mb NUMBER,
max_mb NUMBER
);
INSERT INTO tbs_hist
SELECT TRUNC(SYSDATE), m.tablespace_name,
m.used_space * 8192 / 1024 / 1024,
m.tablespace_size * 8192 / 1024 / 1024,
(SELECT SUM(maxbytes) / 1024 / 1024
FROM dba_data_files d
WHERE d.tablespace_name = m.tablespace_name)
FROM dba_tablespace_usage_metrics m;
COMMIT;
积累数据后,用线性回归或简单差值估算“剩余可用天数”。假设某业务表空间当前已用 620 GB,文件上限合计 800 GB,近 14 天日均增长 3.2 GB,则剩余可增长空间为 180 GB,预计约 56 天触顶。若该表空间 autoextensible=NO,则剩余空间就是 800 GB 减去当前 bytes,触顶后直接报 ORA-01653,业务写入立即失败,属于高优先级风险。
还要区分“表空间整体水位”和“单文件水位”。一个表空间有 4 个数据文件,其中 3 个已满、1 个还有余量,整体使用率可能只有 70%,但新增段只能落在未满文件上,实际可用空间被严重高估。因此文件级检查不可省略,尤其要关注 maxbytes 是否被设成了 32 GB 这类偏小的值。
三、临时表空间:关注峰值而非均值
临时表空间的使用具有强烈的时段性,白天报表、夜间批处理、月末结算的峰值差异可能达到数倍。用均值判断会严重低估风险。正确做法是采集峰值:
SELECT tablespace_name,
ROUND(allocated_space / 1024 / 1024, 1) AS alloc_mb,
ROUND(free_space / 1024 / 1024, 1) AS free_mb,
ROUND((allocated_space - free_space) / 1024 / 1024, 1) AS used_mb
FROM dba_temp_free_space;
更可靠的方式是结合 AWR 的临时段统计,查看 TEMP 表空间的历史峰值分配。若某实例临时表空间总容量 200 GB,日常使用 30 GB,但月末批处理峰值达到 190 GB,则风险不在“平均水位”,而在“峰值窗口”。此时应优先考虑:把大排序 SQL 的 PGA 参数调优、拆分批处理、或为临时表空间增加文件并设置合理的 maxbytes,而不是简单扩容了事。
临时表空间还有一个易被忽略的点:临时文件通常 autoextensible=YES,但 maxbytes 若等于当前 bytes,实际等同于不可扩展。检查时必须同时看这两个字段。
四、UNDO 表空间:看保留时间与峰值事务
UNDO 的容量需求由三个因素决定:UNDO_RETENTION 保留时间、峰值并发事务的生成速率、以及查询所需的读一致性时间。UNDO 表空间过小会导致 ORA-01555 快照过旧,过大则浪费存储。可用如下查询观察 UNDO 使用与最长查询时间的关系:
SELECT begin_time, end_time,
undoblks, maxquerylen, tuned_undoretention
FROM v$undostat
ORDER BY begin_time DESC
FETCH FIRST 12 ROWS ONLY;
若 maxquerylen 经常接近或超过 tuned_undoretention,说明 UNDO 保留时间不足以支撑最长查询,ORA-01555 风险上升。此时应评估是提高 UNDO_RETENTION,还是优化长查询。UNDO 表空间同样要检查 autoextensible 与 maxbytes,并确认没有其他表空间误用了 UNDO 类型的段。
五、把三类表空间合并成风险清单
采集完成后,按“使用率、剩余可增长空间、自动扩展上限、预计触顶天数、峰值余量”五个维度打分,形成可执行的风险清单。下面是一份示例判断表(数据为教学假设值):
| 表空间 | 类型 | 已用/上限 | 自动扩展 | 预计触顶 | 风险等级 |
|---|---|---|---|---|---|
| APP_DATA | 永久 | 620G / 800G | YES,max 800G | 约 56 天 | 高 |
| APP_IDX | 永久 | 180G / 200G | NO | 约 12 天 | 紧急 |
| TEMP | 临时 | 峰值 190G / 200G | YES,max 200G | 峰值窗口内 | 高 |
| UNDOTBS1 | UNDO | 42G / 60G | YES,max 60G | 约 90 天 | 中 |
这张表的价值在于把“使用率”翻译成“还有多少天可用”,并明确每个风险的处置方向:APP_IDX 需要立即扩容或开启自动扩展;TEMP 需要优化峰值 SQL 或扩容;APP_DATA 需要纳入月度扩容计划;UNDOTBS1 保持观察并核对 UNDO_RETENTION。
最后强调一点:容量分析不是一次性动作。建议把上述采集脚本做成每日定时任务,保留至少 30 天历史,并设置两级告警——使用率超过 80% 或预计触顶天数小于 30 天时触发预警,使用率超过 90% 或预计触顶小于 7 天时触发紧急告警。这样容量风险才能从“事后救火”转为“事前可见”。