当前位置: 代码网 > it编程>数据库>Oracle > Oracle数据库中锁等待与会话阻塞故障排查与解决

Oracle数据库中锁等待与会话阻塞故障排查与解决

2026年09月08日 Oracle 我要评论
凌晨两点,告警群突然炸了:订单服务大面积超时,数据库 cpu 不算高,但应用线程池被打满。登录数据库一查,发现大量会话状态是 waiting,等待事件集中在 enq: tx - row lock co

凌晨两点,告警群突然炸了:订单服务大面积超时,数据库 cpu 不算高,但应用线程池被打满。登录数据库一查,发现大量会话状态是 waiting,等待事件集中在 enq: tx - row lock contention。这不是性能慢,而是典型的锁等待与会话阻塞事故。本文结合真实复盘经验,梳理一套可直接落地的排查步骤,帮你在黄金时间内快速止血、定位根因。

一、先止血:快速识别“锁源”

锁问题的核心,永远是找到阻塞源头(blocker) ,而不是盲目杀会话。

1. 查看当前阻塞关系

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 contention
  • seconds_in_wait:已经等了多久

2. 定位顶层阻塞者(root blocker)

很多时候是“连环堵”,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;

这个查询返回的,就是没有被人阻塞、但正在阻塞别人的会话,通常是事故源头。

3. 紧急止血:谨慎杀会话

确认是异常会话后,可临时 kill:

alter system kill session 'sid,serial#' immediate;

注意:

  • 优先杀源头会话,而不是被阻塞的“受害者”
  • 涉及事务的会话被 kill 后会回滚,大事务回滚期间仍可能持续占用资源
  • 生产环境务必确认会话对应的业务模块,避免误杀核心任务

二、再定位:搞清楚“卡在哪”

找到阻塞会话后,下一步是确认它在做什么、锁了什么对象。

1. 查看会话正在执行的 sql

select sql_id, sql_text
from v$sql
where sql_id = '上一步拿到的sql_id';

常见场景:

  • 未提交的 update / delete
  • 长事务中忘记 commit
  • 批量更新缺少索引,导致锁范围放大

2. 查看被锁的对象

select
    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 含义速查:

  • 2:row share(rs)
  • 3:row exclusive(rx)
  • 4:share(s)
  • 5:share row exclusive(srx)
  • 6:exclusive(x)—— 最严格,极易引发阻塞

3. 查看事务与回滚段

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 锁等待的高频根因集中在以下几类:

1. 忘记提交事务(最高频)

开发人员手动在 pl/sql developer 中执行了 update,改完数据后去开会、吃饭、下班,会话一直挂着,锁迟迟不释放。

典型特征

  • 阻塞会话 statusinactive
  • eventsql*net message from client
  • 事务开始时间很早

优化建议

  • 应用使用连接池时,连接归还前必须 commit/rollback
  • 禁止在线上手工执行 dml 后长时间不提交
  • 设置 idle_time 资源限制,自动清理长期空闲会话

2. 大事务批量更新

一次性更新几十万行,且没分批提交,导致:

  • 持有锁时间过长
  • 回滚段暴涨
  • 阻塞其他会话

优化建议

  • 批量更新改为 forall + limit
  • 每 1000~5000 行 commit 一次
  • 低峰期执行,并提前通知 dba

3. 索引缺失导致锁升级

update t_order set status = 'paid' where order_no = 'xxx'

如果 order_no 没有唯一索引,oracle 会锁定更多行,甚至全表扫描时的锁范围会大幅放大。

优化建议

  • 高频更新字段必须有索引
  • 避免 update 条件走全表扫描

4. 并发设计不合理

多个线程同时更新同一行数据,例如秒杀场景下的库存扣减,没有使用:

  • select ... for update nowait
  • 或者应用层分布式锁

导致大量会话互相等待。

优化建议

  • 热点行更新尽量串行化
  • 使用 skip locked 实现队列化处理
  • 业务层做幂等和重试控制

5. ddl 引发的阻塞

alter tablecreate index 等 ddl 需要表级锁,会阻塞所有 dml。

优化建议

  • ddl 必须在维护窗口执行
  • 使用 online 选项(如 create index online
  • 执行前检查 v$locked_object

四、标准化排查 sop(可直接照抄)

遇到锁等待告警,按以下顺序操作,通常 10 分钟内可以定位问题:

确认现象

  • 应用超时增多
  • 数据库 cpu 不高
  • 等待事件集中在 enq: tx - row lock contention

找阻塞源

  • 执行“顶层阻塞者”查询
  • 记录 sidserial#sql_id

判断会话状态

  • active:正在执行 sql,可能是慢 sql 或大事务
  • inactive:多半是忘记提交

定位 sql 与对象

  • v$sql 获取 sql 文本
  • v$locked_object 确认锁表

沟通与决策

  • 联系相关开发或业务方
  • 确认是否可以 kill
  • 必要时上报值班领导

事后处理

  • kill 会话
  • 监控回滚进度
  • 记录事故时间线

五、防患于未然:运维侧建议

  • 开启 awr,保留至少 7 天快照,便于事后回溯
  • 配置锁等待告警(如阻塞会话超过 30 秒触发告警)
  • 定期巡检长事务:v$transaction.start_time
  • 对核心表建立索引审计,避免锁范围失控
  • 推动开发规范:禁止长事务、强制短事务、dml 必须提交

六、复盘总结模板(可直接用)

每次事故后,建议输出一份简短复盘:

故障时间:2026-08-xx 02:15 ~ 02:40

影响范围:订单服务超时,影响约 3% 请求

根因:开发人员在测试环境误连生产,执行 update 后未提交

处理动作:kill sid=1234 会话,事务回滚耗时 2 分钟

改进项

  1. 生产账号禁用 dml 权限
  2. 增加锁等待告警阈值
  3. 培训开发规范:dml 必须显式提交

到此这篇关于oracle数据库中锁等待与会话阻塞故障排查与解决的文章就介绍到这了,更多相关oracle锁等待与会话阻塞内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com