v$undostat能准确计算每秒undo块生成速率,而dba_tablespace_usage_metrics仅反映瞬时使用率,无法体现变化速度,易导致ora-01555等风险误判;应通过sum(undoblks)/sum((end_time-begin_time)86400)算平均速率,或max(undoblks/((end_time-begin_time)86400))算峰值速率。
直接看 v$undostat 里的 undoblks 和时间差,就能算出每秒回滚块生成速率 —— 这是监控 undo 吞吐量最准、最常用的方法。
为什么不能只看 DBA_TABLESPACE_USAGE_METRICS?
这个视图只给当前瞬时使用率(USED_SPACE/TOTAL_SPACE),不反映“变化速度”。Undo 空间可能 80% 空闲,但某条大事务正以每秒 200 块的速度狂写 undo,10 秒就撑爆。光看静态占比会严重误判风险。
真正要防的是 ORA-01555 或空间争用,这取决于 undo 的“产出速率”和“保留时长”的匹配程度,而不是当前用了多少 MB。
怎么从 V$UNDOSTAT 算每秒 undo block 生成量?
核心逻辑:把过去 N 天所有采样周期的 UNDOBLKS 加起来,除以对应总秒数。Oracle 每 10 分钟一条记录,END_TIME - BEGIN_TIME 就是 600 秒(但实际可能有微小漂移,所以必须用字段计算)。
常用两种口径:
-
平均速率(稳态参考):
SELECT ROUND(SUM(undoblks) / SUM((end_time - begin_time) * 86400), 2) AS "ups_blocks_per_sec" FROM v$undostat;
-
峰值速率(容量规划用):
SELECT ROUND(MAX(undoblks / ((end_time - begin_time) * 86400)), 2) AS "peak_ups" FROM v$undostat;
注意:这里用MAX(...)直接找单个 10 分钟内最高的每秒产出,比取MAX(undoblks)再除 600 更准,因为某些周期 end_time-begin_time 可能略大于 600(如统计延迟)。
常见错误和坑点
V$UNDOSTAT 默认只保留最近 7 天(1008 行)数据,但实际保留时长受 _undo_autotune 和内存压力影响,有时会提前被覆盖。如果查不到业务高峰期的数据,不是没发生,很可能是被刷掉了。
以下情况会导致计算失真:
- 数据库刚启动不久,
v$undostat数据不足(少于 10 条),此时SUM((end_time - begin_time) * 86400)会远小于真实跨度; - RAC 环境下,每个实例有自己的
v$undostat,必须在各节点分别执行,不能只查一个; - 如果
undo_retention被设为 0 或极小值(如 1),MAXQUERYLEN会失真,连带影响对保留需求的判断; -
UNDOBLKS统计的是分配的 block 数,不是实际写入字节数 —— 它不含空闲块或未格式化块,所以结果偏保守,但足够用于容量估算。
结合 db_block_size 算真实字节吞吐量
有了每秒 block 数(UPS),再乘上 db_block_size,就能得到字节级吞吐:
SELECT ROUND(ups.ups_val * p.value, 2) AS "bytes_per_sec", ROUND(ups.ups_val * p.value / 1024 / 1024, 2) AS "mb_per_sec" FROM ( SELECT SUM(undoblks) / SUM((end_time - begin_time) * 86400) AS ups_val FROM v$undostat ) ups, v$parameter p WHERE p.name = 'db_block_size';
这个结果可直接代入官方公式 UndoSpace = [UR * (UPS * DBS)] + (DBS * 24) 做空间预估。注意:UR 是 undo_retention 值,DBS 就是上面查出的 db_block_size。
别漏掉那个 + (DBS * 24) —— 它是 Oracle 预留的 overhead,实测中跳过它,扩容后仍可能遇到 NOSPACEERRCNT > 0。











