Oracle Undo问题总结(两类Undo表空间不足和单个会话占用大量Undo的性能问题)

Oracle Undo问题总结(两类Undo表空间不足和单个会话占用大量Undo的性能问题)

一、Undo表空间两类空间不足问题

1、问题分类与快速诊断

Undo表空间不足主要分为两类,影响各不相同。首先,通过以下SQL快速掌握空间使用概况:

sql 复制代码
-- 1. 查看当前实例Undo空间使用情况(Active和Unexpired占比)
SELECT b.tablespace_name,
       NVL(used_undo,0) "USED_UNDO(M)",
       total_undo "Total_undo(M)",
       TRUNC(NVL(used_undo,0) / total_undo * 100, 2) || '%' used_PCT
FROM (
    SELECT NVL(SUM(bytes / 1024 / 1024), 0) used_undo, tablespace_name
    FROM dba_undo_extents
    WHERE status IN ('ACTIVE','UNEXPIRED')
    GROUP BY tablespace_name
) a,
(
    SELECT tablespace_name, SUM(bytes / 1024 / 1024) total_undo
    FROM dba_data_files
    WHERE tablespace_name IN (
        SELECT value
        FROM v$spparameter
        WHERE name = 'undo_tablespace'
        AND (sid = (SELECT instance_name FROM v$instance) OR sid = '*')
    )
    GROUP BY tablespace_name
) b
WHERE a.tablespace_name (+) = b.tablespace_name;

-- 2. 按状态查看各类型Undo区占用空间(GB)
SELECT tablespace_name, status, SUM(bytes/1024/1024/1024) GB
FROM dba_undo_extents
GROUP BY tablespace_name, status;
问题类型 特征 核心影响
ACTIVE类型过高 dba_undo_extentsACTIVE状态的区占比巨大 直接导致Undo表空间无法扩展,DML操作可能因无法分配新区而失败(ORA-30036)。
UNEXPIRED类型过高 UNEXPIRED状态的区占比巨大 虽不会立即导致扩展失败,但会引发性能急剧下降。Oracle为维持DML,会强制重用UNEXPIRED区,此过程开销巨大,导致数据库整体缓慢。
2、ACTIVE类型过高:原因与处理

根本原因:存在长时间未提交的大型事务,或存在生成海量Undo信息的操作,导致ACTIVE区无法被释放和重用。

处理步骤

  1. 紧急处理:临时为Undo表空间添加数据文件,以恢复业务。

    sql 复制代码
    ALTER TABLESPACE undo1 ADD DATAFILE '/path/to/undo2.dbf' SIZE 2G AUTOEXTEND ON NEXT 100M MAXSIZE 30G;
  2. 根本诊断:找出占用Undo的根源会话。执行以下查询,定位消耗Undo最大的会话:

    sql 复制代码
    -- 查看系统中会话使用的回滚段及Undo占用(MB)
    SELECT r.name rbs,
           NVL(s.username, 'None') oracle_user,
           s.osuser client_user,
           p.username unix_user,
           s.sid, s.serial#, p.spid unix_pid,
           s.MACHINE, s.PROGRAM, s.MODULE,
           t.used_ublk * TO_NUMBER(x.value) / 1024 / 1024 AS undo_mb,
           TO_CHAR(s.logon_time, 'mm/dd/yy hh24:mi:ss') AS login_time,
           TO_CHAR(SYSDATE - (s.last_call_et) / 86400, 'mm/dd/yy hh24:mi:ss') AS last_txn,
           t.START_TIME transaction_starttime
    FROM v$process p,
         v$rollname r,
         v$session s,
         v$transaction t,
         v$parameter x
    WHERE s.taddr = t.addr
      AND s.paddr = p.addr
      AND r.usn = t.xidusn(+)
      AND x.name = 'db_block_size'
    ORDER BY undo_mb DESC;
  3. 应用调整 :根据诊断信息(会话连接的MACHINEPROGRAMMODULE以及历史SQL),联系应用方进行针对性优化:

    • OLTP系统:单个会话通常不应超过100MB。如超标,需重点优化其SQL语句(减少更新行数、增加索引减少扫描范围等)。
    • OLAP系统:允许大型分析操作占用较多Undo,但应评估其必要性,优化分区或批量处理逻辑。

提示 :查询v$open_cursorv$active_session_history可关联查询会话历史执行的SQL,辅助定位。

3、UNEXPIRED类型过高:原因与处理

根本原因UNDO_RETENTION(保留时间)设置过长,或Oracle的自动调整(Automatic Tuning)导致保留时间被人为拉长,使得大量已提交的Undo区(状态为UNEXPIRED)无法被快速重用。

诊断指标 :检查v$undostat视图中的unxpblkreucnt列。

sql 复制代码
SELECT BEGIN_TIME, END_TIME, UNXPBLKREUCNT, TUNED_UNDORETENTION
FROM v$undostat
WHERE UNXPBLKREUCNT > 0; -- 该值大于0,表明存在因空间压力而强制重用UNEXPIRED区的情况。
  • UNXPBLKREUCNT > 0明确信号,说明系统正在因Undo空间压力而重用Unexpired区,这会导致性能下降。

处理策略

  1. 临时缓解:同样可先临时添加数据文件。
  2. 调整参数
    • 检查并适当降低 undo_retention参数值(例如从4小时降为1小时)。
    • 在11g及以后版本,考虑禁用Undo自动调整 功能(设置隐含参数_undo_autotune = FALSE),以避免数据库自动将保留时间调得过高。此操作需在充分测试后进行。关于这个隐含参数,详见《Oracle enq: US - contention 等待事件总结》这篇文章。
  3. 检查BUG:查阅Oracle Support,确认是否存在相关BUG导致Unexpired区无法正常释放。

注意:通过切换实例使用的Undo表空间来"重置"状态也是一种方法,但本文不深入讨论。


二、单个Session占用大量Undo------导致性能下降

1、问题现象与根本原因

典型现象

  • 数据库出现大量latch: undo global datawait for a undo record等Undo相关等待事件。
  • CPU资源急剧飙升,可能达到100%。
  • 业务响应极度缓慢,几乎停滞。

根本原因链条

  1. 大事务产生:会话A在事务中对某张表(表T)进行DML操作,产生大量Undo信息(通常超过100M,高并发下50M即可能引发问题)。
  2. 并发访问冲突 :在同一时刻(会话A的事务尚未提交),大量其他会话(B、C、D...)需要访问表T中被会话A修改的数据块。
  3. 读一致性开销:为满足读一致性,所有并发会话都必须去读取会话A产生的巨大Undo段来构造CR块。
  4. 资源耗尽 :巨量的CR块构建操作争抢Undo全局锁(latch: undo global data),导致CPU耗尽,数据库整体性能雪崩。
2、引申现象与诊断

引申现象一 :数据库中大量等待,但在当前实例查询v$transaction未发现大事务。

  • 原因 :可能是RAC其他实例的会话产生的大事务导致。
  • 对策:检查所有实例。

引申现象二:所有实例均未发现活动的大事务,但性能问题依旧。

  • 原因 :产生问题的会话已经提交(COMMIT),但性能雪崩的连锁效应仍在持续。即使根源消除,系统也需要很长时间才能从资源耗尽的队列中恢复。
  • 对策:此为最棘手情况,需采取后续强制干预手段。
3、解决与加速回滚策略

第一步:识别并处理根源会话

查询所有实例的大事务会话。

复制代码
-- 查看系统中会话使用的回滚段及Undo占用(MB)
SELECT r.name rbs,
       NVL(s.username, 'None') oracle_user,
       s.osuser client_user,
       p.username unix_user,
       s.sid, s.serial#, p.spid unix_pid,
       s.MACHINE, s.PROGRAM, s.MODULE,
       t.used_ublk * TO_NUMBER(x.value) / 1024 / 1024 AS undo_mb,
       TO_CHAR(s.logon_time, 'mm/dd/yy hh24:mi:ss') AS login_time,
       TO_CHAR(SYSDATE - (s.last_call_et) / 86400, 'mm/dd/yy hh24:mi:ss') AS last_txn,
       t.START_TIME transaction_starttime
FROM v$process p,
     v$rollname r,
     v$session s,
     v$transaction t,
     v$parameter x
WHERE s.taddr = t.addr
  AND s.paddr = p.addr
  AND r.usn = t.xidusn(+)
  AND x.name = 'db_block_size'
ORDER BY undo_mb DESC;

评估完成进度 :若事务即将完成(>60%),可等待;若进度缓慢(<60%),考虑KILL SESSION

预估回滚时间 :使用以下查询评估KILL后回滚所需时间。

sql 复制代码
-- 查询回滚进度与预计完成时间
SELECT usn, state, 
       undoblockstotal "Total", 
       undoblocksdone "Done", 
       undoblockstotal-undoblocksdone "ToDo",
       DECODE(cputime, 0, 'unknown', 
              SYSDATE + (((undoblockstotal - undoblocksdone) / (undoblocksdone / cputime)) / 86400)) 
              "Estimated time to complete"
FROM v$fast_start_transactions;

-- 或使用匿名块估算(需替换USN和SLOT)
DECLARE
    l_start NUMBER;
    l_end NUMBER;
BEGIN
    SELECT ktuxesiz INTO l_start FROM x$ktuxe WHERE KTUXEUSN=194 AND KTUXESLT=17;
    DBMS_LOCK.SLEEP(60);
    SELECT ktuxesiz INTO l_end FROM x$ktuxe WHERE KTUXEUSN=194 AND KTUXESLT=17;
    DBMS_OUTPUT.PUT_LINE('time est Day:'|| ROUND(l_end/(l_start - l_end)/60/24, 2));
END;
/

第二步:根据场景选择加速回滚策略

场景 可行策略 说明
可以重启数据库 1. 设置fast_start_parallel_rollback=HIGH 2. 增加_cleanup_rollback_entries(默认100,可调至400-800) 3. 重启后等待回滚完成。 回滚并行度需重启生效;增加参数值可减少事务表扫描开销。
可停止相关应用 1. 停止访问问题表的应用,KILL残留连接。 2. 设置回滚并行度为HIGH。 3. 回滚完成后重启应用。 停止应用可释放CPU资源给回滚进程,加速回滚速度。
数据库/应用均不可停 RENAME替换表(业务如果可行,最推荐方法) : 1. RENAME正在回滚的大表为备份名。 2. 新建同名空表(需处理索引、约束、依赖)。 3. KILL等待Undo的会话,释放CPU。 4. 分批将数据从备份表插回新表。 此方法使新查询访问空表,绕过回滚等待,快速恢复业务。数据恢复需谨慎分批,避免再次产生大事务。

常见观点

  • 回滚并行度 :在CPU 100%时,调整此参数无法即时加速,因资源已耗尽。
  • 禁用SMON回滚oradebug event 10513):因性能问题源于查询的读一致性,而非SMON回滚本身,故无法解决此类问题。
  • 增加_cleanup_rollback_entries :需重启生效,无法及时处理
预防与监控
  • OLTP系统不应出现单会话高Undo占用。需部署监控,一旦超过阈值(如100M)即告警,并优化相关SQL或应用逻辑。
  • OLAP系统:允许大事务,但需评估并发访问风险。若存在报表与分析混合负载,应考虑资源隔离或时间窗口分离。
  • 监控SQL:定期执行第一部分中的会话Undo使用查询,建立基线。
相关推荐
企业数字化笔记1 小时前
固定资产财务账与实物账怎么对账?折旧快照、差异检测与SQL核对
android·数据库·sql
DBA_G1 小时前
GBase 8a表空间多路径存储数据迁移链路适配解析
数据库·oracle
java1234_小锋1 小时前
Tornado 6.5,全面支持 Python 3.14
数据库·python·tornado
jyOverQ1 小时前
MySQL 事务到底是什么?ACID 四大特性与隔离级别怎么理解?
数据库·mysql
SelectDB2 小时前
Doris 直查 Paimon 索引:快手湖上向量检索的共建与落地
大数据·数据库·数据分析
风123456789~2 小时前
【Oracle专栏】全局 && 本地复合索引 实验
数据库·oracle
1314lay_10072 小时前
通过Sql Server创建EXCEL文件:master..xp_cmdshell
数据库·excel
zzzll11112 小时前
用 DeepSeek Harness 手搓一个自己的 Agent
数据库
名字还没想好☜3 小时前
Spring @EventListener 事件驱动解耦实战:同步转异步、事务绑定与顺序控制
java·数据库·后端·python·spring