【故障处理】队列等待之enq: US - contention案例

来源:这里教程网 时间:2026-03-03 17:45:52 作者:

  BLOG 文档结构图

wps6E72.tmp  

 

  前言部分

2.1    导读和注意事项

各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识, ~O(∩_∩)O~

① enq: US - contention 等待事件的解决

② 一般等待事件的解决办法

③ 队列等待的基本知识

  Tips:

① 本文在 ITpub http://blog.itpub.net/26736162 )、博客园 ( http://www.cnblogs.com/lhrbest )和微信公众号( xiaomaimiaolhr )有同步更新

② 文章中用到的所有代码,相关软件,相关资料请前往小麦苗的云盘下载( http://blog.itpub.net/26736162/viewspace-1624453/

③  若文章代码格式有错乱,推荐使用搜狗 360 或QQ 浏览器,也可以下载 pdf 格式的文档来查看, pdf 文档下载地址: http://blog.itpub.net/26736162/viewspace-1624453/ ,另外 itpub 格式显示有问题,可以去博客园地址阅读

④  本篇 BLOG 中命令的输出部分需要特别关注的地方我 都用 灰色背景和粉红色字体 来表 示,比如下边的例子中, thread 1 的最大归档日志号为 33 thread 2 的最大归档日志号为 43 是需要特别关注的地方;而命令 一般使用 黄色背景和红色字体 注;对代码或代码输出部分的注 释一般采用 蓝色字体 表示

 

本文如有错误或不完善的地方请大家多多指正, ITPUB留言或QQ皆可,您的批评指正是我写作的最大动力。

 

  故障分析及解决过程

 

3.1    故障环境介绍

 

项目

source db

db  类型

RAC

db version

11.2.0.4.0

db  存储

ASM

OS版本及 kernel 版本

AIX 64位  7.1.0.0

 

3.2    故障发生现象及报错信息

最近系统做压测,碰到的问题比较多,今天同事发了个 AWR 报告,说是系统响应很慢,我简单看了下,简单分析下吧:

wps6E83.tmp  

270分钟时间而 DB Time 2000 多分钟, DB Time 太高了,负载很大,很可能有异常的等待事件,系统配置还是比较牛逼的。

wps6E84.tmp  

事务量很大,其它个别参数有点问题,不一一解说了。 等待事件很明显了:

wps6E85.tmp  

AWR的其它部分就不分析了,首先 这个等待事件: enq: US - contention 比较少见,查了一下 资料,有点收获:

SELECT   *   FROM  V$EVENT_NAME  WHERE   NAME   =   'enq: US - contention' ;

wps6E86.tmp  

  SELECT   *   FROM  v$lock_type d  WHERE  d.TYPE = 'US' ;

wps6E87.tmp  

"enq: US - contention" ,这个 event 说明事务在队列中等待 UNDO Segment ,通常是由于 UNDO 空间不足导致的。

在对此事件说明之前,需要理解在使用 AUM atuomatic undo management )时,回滚段在何时联机或脱机。 AUM RBU rollback segment management )不同,回滚段的管理 O racle 自动完成的。使用 AUM 时,回滚段的联机或脱机的时刻如下:

1 )在执行 alter database open 的时候将回滚段联机

2 )通过 alter system set undo_tablespace=xxx  修改撤销表空间时,将原来的回滚段脱机后,再将新的回滚段联机。

3 )通过 SMON ,自动脱机或者联机回滚段,如果一段时间内,事务量增加,联机状态的回滚段也会增加,一段时间内若是没有实物或事务减少,回滚段就会被 smon 进程脱机。

为了同步将回滚段联机或脱机的过程,执行该工作的服务器进程或后台进程应获得 US 锁,每个回滚段非配一个 US 锁, ID1=Undo segment# 。若在获得 US 锁的过程中发生争用,则等待 enq US-contention 事件。服务器进程应该在开始事务时分配到回滚段,但如果不存在可用的回滚段时,应该创建新的回滚段或将脱机状态的回滚段联机。在实现此项工作期间,服务器进程为了获得 US 锁而等待,等待占有可用回滚段。

这是 oracle10g 中开始出现的 bug( 11.1.0.7 中仍有这个 BUG) ,当因为系统 activity 增加或者降低的时候, oracle SMON 进程会自动 ONLINE 或者 OFFLINE rollback segments 。这样导致某些与 undo segments 相关的 latch 或者 enqueue hold 住太长时间,导致系统很多活跃 session 都开始等待 enq: US - contention 。可以同时使用以下解决方法 :

1.  设置 event SMON 不自动 OFFLINE 回滚段

alter system set events '10511 trace name context forever, level 1';

 

2.  设置参数 _rollback_segment_count  :表示有多少 rollback segment 要处于 online 的状态;可以将该数值设置为数据库最繁忙的时候的回滚段数目。

alter system set "_rollback_segment_count"=1000 SID='*';

这里以 _ 开头的为隐藏参数,通过 show parameter  是看不到的,可以通过以下语句:

select a.ksppinm name, b.ksppstvl value, a.ksppdesc description
from xksppia,xksppia,xksppcv b
where a.indx = b.indx
and a.ksppinm like '%_rollback_segment_count%';

 

3.  undo autotune bug 多多。最好 disable

alter system set "_undo_autotune"= false;

这种方法就是关闭了 UNDO 的自动调整功能, 同时 也能解决掉 UNDO 表空间会在很长时间都一直保持着使用率是接近 100% 的问题。

 

4.   有一个 patch: A fix to bug 7291739 is to set a new hidden parameter, _highthreshold_undoretention to set a high threshold for undo retention completely distinct from maxquerylen.

alter system set "_highthreshold_undoretention"=;

 

5.   增加undo 表空间

alter tablespace UNDOTBS1 add datafile '+DATA1' size 30G;

 

6.   设置undo表空间的 NOGUARANTEE

select tablespace_name, retention from dba_tablespaces where tablespace_name like 'UNDO%';

ALTER TABLESPACE UNDOTBS RETENTION NOGUARANTEE;

 

7.   减少UNDO_RETENTION 的时间

SQL> show parameter undo

NAME                                  TYPE         VALUE

------------------ ---------------------- --------

undo_management                     string        AUTO

undo_retention                      integer       10800

 

8.   重启数据库节点

 

3.3    故障分析及解决

我们查询 ASH 视图看看当时的情况:

  SELECT  D.SQL_ID , CHR ( BITAND ( P1 ,   - 16777216 )   /   16777215 )   ||

         CHR ( BITAND ( P1 ,   16711680 )   /   65535 )  "Lock" ,

         BITAND ( P1 ,   65535 )  "Mode" ,   COUNT ( 1 ), COUNT ( DISTINCT  d.session_id  )

   FROM  DBA_HIST_ACTIVE_SESS_HISTORY D

  WHERE  D.SAMPLE_TIME  BETWEEN  TO_DATE ( '2016-09-07 17:39:44' ,   'YYYY-MM-DD HH24:MI:SS' )   AND

       TO_DATE ( '2016-09-07 22:13:41' ,   'YYYY-MM-DD HH24:MI:SS' )

    AND  D.EVENT  =   'enq: US - contention'

  GROUP   BY  D.SQL_ID ,( CHR ( BITAND ( P1 ,   - 16777216 )   /   16777215 )   ||

         CHR ( BITAND ( P1 ,   16711680 )   /   65535 )),( BITAND ( P1 ,   65535 ));

wps6E98.tmp  

LOCK为 US MODE 6 ,看看具体的 SQL 内容:

  SELECT  A.SQL_TEXT ,  A.EXECUTIONS ,  A.MODULE ,  A.SQL_ID

  FROM  V$SQL A

WHERE  A.SQL_ID  IN   ( '5ww8x9u15a90y' ,

  'ayngk81z8fh0m' ,

  '1cmnjddakrqbv' ,

  '26ad9zvt5xgb3' );

wps6E99.tmp  

看看时间段是哪个区间:

SELECT  D.SQL_ID ,  TO_CHAR ( D.SAMPLE_TIME ,   'YYYY-MM-DD HH24:MI' ),   COUNT ( 1 )

   FROM  DBA_HIST_ACTIVE_SESS_HISTORY D

  WHERE  D.EVENT  =   'enq: US - contention'

    AND  D.SQL_ID  IN   ( '5ww8x9u15a90y' ,   '26ad9zvt5xgb3' )

  GROUP   BY  D.SQL_ID ,  TO_CHAR ( D.SAMPLE_TIME ,   'YYYY-MM-DD HH24:MI' );

wps6E9A.tmp  

看来问题几种在这 2分钟之内。 基本都是对同一个表做插入或者更新操作:

  SELECT   DISTINCT  D.CURRENT_OBJ#

    FROM  DBA_HIST_ACTIVE_SESS_HISTORY D

   WHERE  D.SAMPLE_TIME  BETWEEN

        TO_DATE ( '2016-09-07 17:39:44' ,   'YYYY-MM-DD HH24:MI:SS' )   AND

        TO_DATE ( '2016-09-07 22:13:41' ,   'YYYY-MM-DD HH24:MI:SS' )

     AND  D.EVENT  =   'enq: US - contention'

   GROUP   BY  D.CURRENT_OBJ# ;

SELECT   *   FROM  DBA_OBJECTS a  WHERE  a.object_id  IN    ( '87620' , '87632' , '87663' , '87667' , '87686' , '87684' , '87688' , '87626' , '87646' , '87642' , '87639' , '87661' , '87628' , '87675' , '87643' , '87677' , '87660' , '87631' , '87629' , '87668' , '87682' , '87685' , '87654' , '87640' , '87627' , '87636' , '87664' , '87655' , '87645' , '87637' , '87669' , '87673' , '87666' , '87634' , '87644' , '87672' , '87648' , '87649' , '87662' , '87651' , '87641' , '87653' , '87659' , '87680' , '87681' , '0' , '87625' , '87670' , '87658' , '87674' , '87671' , '87633' , '87679' , '87647' );

wps6E9B.tmp  

 

可以看到操作的表是一个分区表。

解决方案:

alter tablespace UNDOTBS1 add datafile '+DATA1' size 30G;

alter system set events '10511 trace name context forever,level 1';

ALTER SYSTEM SET "_rollback_segment_count"=1000 SID='*';

 

执行之后经过开发进行压测,已经没有该等待事件的产生了:

SELECT  D.SQL_ID ,  TO_CHAR ( D.SAMPLE_TIME ,   'YYYY-MM-DD HH24:MI' ),   COUNT ( 1 )

   FROM  DBA_HIST_ACTIVE_SESS_HISTORY D

  WHERE  D.EVENT  =   'enq: US - contention'  

  GROUP   BY  D.SQL_ID ,  TO_CHAR ( D.SAMPLE_TIME ,   'YYYY-MM-DD HH24:MI' );

 

查询无数据。 转自: 【故障处理】队列等待之enq: US - contention案例_ITPUB博客

相关推荐