行锁,更新冲突,事务没提交。。。
来自真实世界的情况是
-
--查被阻塞会话
-
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服务调用中加入了超时失败事务回滚机制。
阅读(1243) | 评论(0) | 转发(0) |