38人参与 • 2026-09-08 • Oracle
凌晨两点,告警群突然炸了:订单服务大面积超时,数据库 cpu 不算高,但应用线程池被打满。登录数据库一查,发现大量会话状态是 waiting,等待事件集中在 enq: tx - row lock contention。这不是性能慢,而是典型的锁等待与会话阻塞事故。本文结合真实复盘经验,梳理一套可直接落地的排查步骤,帮你在黄金时间内快速止血、定位根因。
锁问题的核心,永远是找到阻塞源头(blocker) ,而不是盲目杀会话。
select
s.sid,
s.serial#,
s.username,
s.status,
s.sql_id,
s.event,
s.wait_class,
s.seconds_in_wait,
s.blocking_session,
s.blocking_session_status
from v$session s
where s.blocking_session is not null
order by s.seconds_in_wait desc;
重点关注:
blocking_session:谁在阻塞我event:等待事件,如 enq: tx - row lock contentionseconds_in_wait:已经等了多久很多时候是“连环堵”,a 堵 b,b 堵 c。要找到最顶层的 a:
select
s.sid,
s.serial#,
s.username,
s.status,
s.sql_id,
s.event,
s.seconds_in_wait
from v$session s
where s.sid in (
select distinct blocking_session
from v$session
where blocking_session is not null
)
and s.blocking_session is null;
这个查询返回的,就是没有被人阻塞、但正在阻塞别人的会话,通常是事故源头。
确认是异常会话后,可临时 kill:
alter system kill session 'sid,serial#' immediate;
注意:
找到阻塞会话后,下一步是确认它在做什么、锁了什么对象。
select sql_id, sql_text from v$sql where sql_id = '上一步拿到的sql_id';
常见场景:
update / deletecommitselect
l.session_id,
l.locked_mode,
o.owner,
o.object_name,
o.object_type
from v$locked_object l
join dba_objects o on l.object_id = o.object_id
order by l.session_id;
locked_mode 含义速查:
select
t.xidusn,
t.xidslot,
t.xidsqn,
t.status,
t.start_time,
t.used_ublk,
s.sid,
s.serial#,
s.username
from v$transaction t
join v$session s on t.addr = s.taddr;
如果看到某个事务 start_time 很早、used_ublk 很大,基本可以判定是长事务惹的祸。
从多次生产事故中总结,oracle 锁等待的高频根因集中在以下几类:
开发人员手动在 pl/sql developer 中执行了 update,改完数据后去开会、吃饭、下班,会话一直挂着,锁迟迟不释放。
典型特征:
status 为 inactiveevent 为 sql*net message from client优化建议:
commit/rollbackidle_time 资源限制,自动清理长期空闲会话一次性更新几十万行,且没分批提交,导致:
优化建议:
forall + limitcommit 一次update t_order set status = 'paid' where order_no = 'xxx'
如果 order_no 没有唯一索引,oracle 会锁定更多行,甚至全表扫描时的锁范围会大幅放大。
优化建议:
update 条件走全表扫描多个线程同时更新同一行数据,例如秒杀场景下的库存扣减,没有使用:
select ... for update nowait导致大量会话互相等待。
优化建议:
skip locked 实现队列化处理alter table、create index 等 ddl 需要表级锁,会阻塞所有 dml。
优化建议:
online 选项(如 create index online)v$locked_object遇到锁等待告警,按以下顺序操作,通常 10 分钟内可以定位问题:
确认现象
enq: tx - row lock contention找阻塞源
sid、serial#、sql_id判断会话状态
active:正在执行 sql,可能是慢 sql 或大事务inactive:多半是忘记提交定位 sql 与对象
v$sql 获取 sql 文本v$locked_object 确认锁表沟通与决策
事后处理
v$transaction.start_time每次事故后,建议输出一份简短复盘:
故障时间:2026-08-xx 02:15 ~ 02:40
影响范围:订单服务超时,影响约 3% 请求
根因:开发人员在测试环境误连生产,执行 update 后未提交
处理动作:kill sid=1234 会话,事务回滚耗时 2 分钟
改进项:
到此这篇关于oracle数据库中锁等待与会话阻塞故障排查与解决的文章就介绍到这了,更多相关oracle锁等待与会话阻塞内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论