在巡检时发现大量undo相关的等待事件,enq: us - contention,latch: undo global data
latch: undo global data一般发生在undo表空间不足时,应急处理为增加undo表空间,或者把undo retention调小(如unexpired extents较多时有效)。
接下来分析一下产生这个问题的原因,由于查看了当前没有大事务,死事务排除活动事务占用的情况,这时推测为过去某个时间点大量undo占用,还未超过undo retention,导致undo extent不能重用。可以通过v$undostat分析这个情况。
select begin_time,(end_time-begin_time)360024 s,undoblks,txncount,maxconcurrency, expstealcnt,expblkrelcnt,expblkreucnt,expiredblks from v$undostat where begin_time>sysdate-1 order by begin_time;
可以看到在问题发生前确实有undoblks分配量,事务量突增的情况,这时可以看一下undo retention,根据这个产生速率算一下是不是有大量undo blocks还未过期。
接下来查找哪些事务导致的undo占用突增。一般可以通过下面两种途径分析
1、ash查找大事务,按xid分组,如果单个xid活动时间过长,或过滤sql_opname in(‘insert’,‘delete’,‘update’),按sql分组,查找是不是有执行量突增的dml。
2、通过分析awr中的seg stats,查询block change突增的对象。
通过上面的分析也没找到异常点,接下来就比较难找了,这里运气比较好,通过对比sql的执行量、执行情况,找到了如下plsql匿名块在undo blocks产生速率高的时间点执行,执行量也与undo blocks的波动一致。以下为伪代码。
declare
cnt number;
begin
for i in 1..100000 loop
select count(*) into cnt from test.tobj@test;<<<<
if cnt>10 then
insert test.t values (cnt);<<<<<后面统计这个insert不怎么执行,cnt>10这个条件不成立。
end if;
commit;
end loop;
end;
一个使用dblink的查询执行量大,insert几平不怎么执行。
这里的问题点
1、每次循环dblink查询会生一个事务(dblink为分布式事务)。
2、每次循环都会提交。
根据之前看到的undostats的统计,undo blocks使用量,事务量的增长,推测为循环dblink查询,每次产生新的分布式事务分配新rollback segment导致undo使用突增。以下在虚拟机模拟验证这一猜测。
可以看到这个循环执行前undo free 270m,执行这个pl/sql块,很快就用完了.(里面的if判断不会成立,insert不会执行)
xidusn xidslot xidsqn 一直在变化,说明频繁产生新事务
used_ublk 为1,每个事务使用1个undo block
sql> @trans
sid serial# username taddr ses_addr used_ublk used_urec 0xflag status start_date xidusn xidslot xidsqn xid prv_xid ptx_xid
---------- ---------- ------------------------------ ---------------- ---------------- ---------- ---------- --------- ----------------------------- ----------------- ---------- ---------- ---------- ---------------- ---------------- ----------------
29 6967 sys 0000000081b40ec8 0000000084693e40 1 1 421603 active 20220211 22:55:55 273 7 682 11010700aa020000 0000000000000000 0000000000000000
中间可以观察到这个session一直在分配新的rollback segment,每次使用一个undo block
sql> @trans
sid serial# username taddr ses_addr used_ublk used_urec 0xflag status start_date xidusn xidslot xidsqn xid prv_xid ptx_xid
---------- ---------- ------------------------------ ---------------- ---------------- ---------- ---------- --------- ----------------------------- ----------------- ---------- ---------- ---------- ---------------- ---------------- ----------------
29 6967 sys 0000000081b06b68 0000000084693e40 1 1 421603 active 20220211 22:56:04 273 6 758 11010600f6020000 0000000000000000 0000000000000000
sql> @trans
no rows selected
sql> @trans
sid serial# username taddr ses_addr used_ublk used_urec 0xflag status start_date xidusn xidslot xidsqn xid prv_xid ptx_xid
---------- ---------- ------------------------------ ---------------- ---------------- ---------- ---------- --------- ----------------------------- ----------------- ---------- ---------- ---------- ---------------- ---------------- ----------------
29 6967 sys 0000000081b9ac18 0000000084693e40 1 1 421603 active 20220211 22:56:09 275 27 760 13011b00f8020000 0000000000000000 0000000000000000
还可以看到这个dblink查询导致了redo的增长。这也是除了延迟块清除之外的另一个查询产生redo的例子。