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_extents中ACTIVE状态的区占比巨大 直接导致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. 应用调整 :根据诊断信息(会话连接的MACHINE、PROGRAM、MODULE以及历史SQL),联系应用方进行针对性优化:

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

提示 :查询v$open_cursor和v$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 data或wait 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使用查询,建立基线。
相关推荐
笨小孩@GF 知行合一3 小时前
易语言-高级应用
数据库·编程·易语言·中文编程
KaiwuDB3 小时前
KaiwuDB 运维实战04:DRBD + KaiwuDB——物联网场景下的低成本数据库高可用方案
运维·数据库·物联网·时序数据库·kaiwudb·aiot·多模数据库
夜雪一千5 小时前
MySQL外键彻底入门:是什么、怎么用、什么时候不该用
数据库·mysql
qq_334466865 小时前
删除SSMS的历史登录记录
数据库·sql
zl_dfq5 小时前
Redis 之 【常见面试题总结】(从数据类型到高可用、缓存一致性全解析)
数据库·redis
龙亘川5 小时前
铭记英烈守初心,数字强基促服务:亘川智城退役军人服务系统的实践与价值
java·数据库·人工智能
kv1106 小时前
Android studio国内开发有关
java·数据库·android studio
哭泣方源炼蛊7 小时前
正则表达式c++内容汇集
数据库·c++·mysql·正则表达式
余槐i7 小时前
EXPLAIN 显示走了索引查询仍慢:回表与选择性在 500 万行表上拉开 10 倍耗时
数据库·postgresql·性能优化·vacuum·explain