行锁,更新冲突,事务没提交。。。
来自真实世界的情况是
-
--查被阻塞会话
-
set lin 200 pages 1000
-
col username for a10
-
col program for a40
-
col event for a30
-
col waiting_session for a20
-
-
with tkf_block_info as
-
(select a.inst_id || '_' || a.sid waiting_session,
-
a.username, a.program, a.event, a.sql_id, a.last_call_et,
-
decode(a.blocking_instance || '_' || a.blocking_session,
-
'_', null, a.blocking_instance || '_' || a.blocking_session) holding_session
-
from gv$session a,
-
(select inst_id, sid
-
from gv$session
-
where blocking_session is not null
-
union
-
select blocking_instance, blocking_session
-
from gv$session
-
where blocking_session is not null) b
-
where a.inst_id = b.inst_id
-
and a.sid = b.sid)
-
select lpad(' ', 3 * (level - 1)) || waiting_session waiting_session,
-
username, program, event, sql_id, last_call_et
-
from tkf_block_info
-
connect by prior waiting_session = holding_session
-
start with holding_session is null;
这是一个阻塞树(先给自己下个拌儿),最上面的实例2 的2235阻塞了其他几个会话,而且这个会话已经空闲状态,等客户端指令。
应该有未结束的事务,可以先搂一眼(繁忙的系统就不要看了)。
-
--未提交的事务
-
col username for a8
-
col machine for a20
-
col program for a25 trunc
-
-
select t.start_time , s.sid, s.serial#, s.username, s.status, s.program,sql_id
-
-- s.machine, s.module,s.osuser,s.terminal,t.ubablk,t.ubarec,t.status
-
, to_char(s.logon_time,'yy/mm/dd hh24:mi:ss') logon_time
-
from v$transaction t, v$session s
-
where s.saddr = t.ses_addr
-
order by start_time;
首要的是判定大家都在争抢啥
-
--看这些session在等什么对象
-
-
col owner for a12
-
col object_name for a30
-
col object_type for a15
-
-
select owner,object_name,object_type from dba_objects where object_id in(
-
select row_wait_obj# /*,row_wait_file#,row_wait_block#,row_wait_row# */ from v$session
-
where event='enq: tx - row lock contention');
用什么语句抢
-
--等待执行的sql
-
col sql_text for a60
-
-
select sid,sql_text from v$session a,v$sql b where event='enq: tx - row lock contention'
-
and (b.sql_id=a.sql_id ) order by 1,2;
如果没判定出原因,那就就从头梳理,先看看锁类型
-
select sid,
-
chr(bitand(p1, -16777216) / 16777215) ||
-
chr(bitand(p1, 16711680) / 65535) "name",
-
(bitand(p1, 65535)) "mode"
-
from v$session_wait
-
where event = 'enq: tx - row lock contention';
再看关联的事务
-
col tx for a30
-
-
select
-
sid, seq#, state, seconds_in_wait,
-
'tx-'||lpad(ltrim(p2raw,'0'),8,'0')||'-'||lpad(ltrim(p3raw,'0'),8,'0') tx,
-
trunc(p2/65536) xidusn,
-
trunc(mod(p2,65536)) xidslot,
-
p3 xidsqn
-
from v$session_wait
-
where event='enq: tx - row lock contention'
waitevent:“enq:tx - 行锁争用”参考说明(文档 id 1966048.1)
回到问题开头,为什么有个
“空闲”会话阻塞了一堆会话呢?
而且进一步跟踪 v$active_session_history中sql_mode<>3(
排除掉查询),也没发现相关操作,根据客户描述是a公司开发的模块阻塞了b公司的更新操作。
为什么 ash中没有发现相关sql ?
不难解释,可能是事务太小,每秒一次的会话信息也没有采样到。
a公司的到底更新了哪些数据呢?
也不用解释,直接查行锁争用事件对应的object即可,详细的可以再查事务。
最关键的疑问:为什么a公司的会话没有提交事务呢?
这个就不好查了,也许防火墙、也许网络中断、也许sql性能差超出连接池的阈值...
应该不是gc收集,因为长时间不释放锁,目前都是 kill 才释放。
检查侦听日志、检查网卡丢包情况、请a公司程序员吃饭...
跟进结果是:阻塞源头的事务是一个应用事务处理,处理中包含有web服务调用,而web服务处理出现故障,一直处于阻塞等待状态,导致事务长时间未提交。
解决思路是:在web服务调用中加入了超时失败事务回滚机制。
阅读(1059) | 评论(0) | 转发(0) |