09 · 锁阻塞与死锁排查:enq: TX 与 ORA-00060
现象极具迷惑性应用卡住不动数据库 CPU 很闲、IO 很闲、AWR Top 1 却是enq: TX - row lock contention。这是应用并发设计问题在数据库里的投影。本篇给出阻塞链三查、死锁处理流程以及 KILL 会话的正确姿势。一、30 秒原理课Oracle 怎么锁行DML 修改某行 → 在行所在数据块记录事务信息ITL 槽→ 其他会话想改同一行就要等第一个事务COMMIT/ROLLBACK这个等待就是enq: TX - row lock contentionOracle 行锁没有锁管理器——锁信息随数据块走所以行锁永远不会锁表撑爆内存另一个产生 TX 等待的场景唯一键冲突插入撞车时也表现为 TX 等待表级的是enq: TM - contention典型如 DDL 撞上未提交的 DML、或子表外键无索引时的级联操作。二、阻塞链三查标准排查 SQL2.1 第一查谁阻塞了谁SELECTsid,serial#, username, event, sql_id, sql_child_number,blocking_session,blocking_session_status,seconds_in_wait,final_blocking_sessionFROMv$sessionWHEREblocking_sessionISNOTNULL;输出直接给出受害者 sid → 加害者 blocking_session的映射多条记录串起来就是阻塞链。2.2 第二查加害者在干什么-- 用阻塞链顶端的 sid 查它的 SQLSELECTsql_fulltextFROMv$sqlWHEREsql_id(SELECTsql_idFROMv$sessionWHEREsidblocker_sid);-- 它的事务开了多久、锁了哪些对象SELECTs.sid,s.serial#, s.username, t.start_time,ROUND(t.used_ublk*8/1024)undo_mb,s.row_wait_obj#FROMv$sessions,v$transactiontWHEREs.taddrt.addrANDs.sidblocker_sid;重点看start_time——事务挂了 3 小时没提交多半是应用忘了 commit 或连接被挂起。2.3 第三查锁的是什么对象-- 行级锁对象把 sid 换成受害者的SELECTo.owner,o.object_name,o.object_typeFROMdba_objects o,v$locked_object lWHEREo.object_idl.object_id;-- 受害者正在等哪一行的数据SELECTs.sid,o.object_name,s.row_wait_file#, s.row_wait_block#, s.row_wait_row#FROMv$sessions,dba_objects oWHEREs.row_wait_obj# o.object_id AND s.sid victim_sid;三、处理KILL 的正确姿势确认加害者是僵死事务应用崩溃残留、忘提交的僵尸连接后ALTERSYSTEMKILLSESSIONsid,serial#IMMEDIATE;⚠️三个纪律别一上来就 KILL如果加害者是正常长事务跑批KILL 它等于制造更大的故障。先确认业务归属分布式事务要谨慎盲 KILL 可能产生 in-doubt 事务需要 DBA 手动COMMIT/ROLLBACK FORCE收尾会话被标记KILLED却不消失OS 层还活着时才需要 OS 层配合# 找到对应 server process只列流程实际操作需确认SELECT p.spid, s.sid, s.program FROMv$processp,v$sessions WHERE p.addrs.paddr;kill-9spid# PMON 会接管并回滚其事务四、死锁 ORA-00060Oracle 已经替你处理了一半死锁 事务 A 锁行 1 等行 2事务 B 锁行 2 等行 1谁也不让谁。Oracle 检测到后会自动回滚其中一个事务不是 KILL 会话应用收到ORA-00060: deadlock detected while waiting for resource。4.1 DBA 要做什么死锁是应用设计问题DBA 的职责是提供破案材料alert.log 里定位ORA-00060时间点打开对应的trace 文件alert.log 中DEADLOCK DETECTED附近会给出路径——里面有完整的两张死锁图各自持有的行、等待的行、当前 SQL、user/OS 信息把材料交给应用通常是两个事务以相反顺序更新同样的两批行或唯一键插入并发、位图索引并发 DML。4.2 常见修复应用侧统一更新顺序所有事务按相同顺序如按主键排序访问行缩小事务范围先查询后更新的事务把查移出事务并发插入唯一键改用序列 异常捕获重试外键无索引引发的 TM/死锁给外键列建索引。五、和锁容易混淆的等待等待本质处理方向enq: TX - row lock contention等另一个事务提交行锁/ITL/唯一键本篇enq: TX - allocate ITL entry块内事务槽不足提高initrans、重建段enq: TM - contention表级DDL 撞 DML、外键无索引加索引、错峰 DDLbuffer busy waits等块上的 IO/构造不是事务锁热块打散、反向键索引library cache lock/pin等 DDL/编译锁查对象级 DDL 冲突、硬解析六、防重于治三个长期措施应用侧连接池超时 事务心跳僵尸连接是阻塞链的最大来源外键一律建索引TM 争用与死锁的经典来源监控固化把阻塞链第一查做成巡检脚本阻塞超 5 分钟告警-- 巡检告警样例SELECTcount(*)FROMv$sessionWHEREblocking_sessionISNOTNULLANDseconds_in_wait300;七、小结enq: TX高 应用并发冲突数据库只是现场三查blocking_session阻塞链 → 加害者 SQL/事务时长 →v$locked_object对象定位KILL 前确认业务归属与分布式事务标记 KILLED 不消失再考虑 OS 层ORA-00060 由 Oracle 自动化解DBA 的任务是拿 trace 给应用修顺序外键索引、连接池治理是长期解。下一篇10-慢SQL分析路径 —— 性能篇收官单条 SQL 的完整分析路径。