oracle知识整理_锁及等待事件SQL_第二部分

各位深耕 Oracle 数据库技术的同行、正在系统学习 Oracle 的同学们,大家好!

在上一期《Oracle 知识整理_锁及等待事件 SQL_第一部分》的分享中,我给大家整理并分享了一批用于锁信息基础查询、等待事件快速统计的实用 SQL 语句。内容发布后,收到了很多朋友的正向反馈,不少读者在评论区和私信里说,这些开箱即用的语句,在日常运维的问题排查中切实帮上了大忙,同时也希望我能补充更多进阶场景、更贴合生产故障实战的相关内容。

熟悉 Oracle 运维与性能优化的朋友都清楚,锁机制是 Oracle 保障事务 ACID 特性、实现数据并发控制与一致性的核心基石,而等待事件则是数据库运行状态最直观的 "晴雨表"。我们日常工作中遇到的绝大多数数据库问题 ------ 从业务接口响应变慢、SQL 执行超时,到高频事务阻塞、会话卡死,甚至是生产环境突发的实例 hang 住、业务大面积中断的严重故障,其根因定位与问题拆解,几乎都绕不开对锁竞争的深度排查,以及对等待事件的精准分析。

也正因这个场景是 Oracle 运维、优化、故障排查中的高频刚需,今天我们继续沿着这个话题深入,给大家带来锁及等待事件相关的进阶内容。本期会补充更多面向实战场景的 SQL 查询语句,覆盖行锁阻塞全链路追踪、死锁快速定位、历史等待事件回溯、特定等待事件深度拆解等高频痛点场景,所有语句均经过生产环境验证,力求拿来即用、落地见效。

希望今天分享的这部分内容,能切实帮助大家在日常的数据库运维工作、故障应急处置、性能优化实践,以及 Oracle 相关的学习与认证备考中,提升排查效率,少走弯路。

1)Oracle 查询被阻塞会话与被阻塞会话的对应sql

复制代码
SELECT S1.USERNAME   "WAITING USER",
       S1.OSUSER     "OS User",
       S1.LOGON_TIME "logon time",
       W.SESSION_ID  "Sid",
       P1.SPID       "PID",
       Q1.SQL_TEXT   "SQLTEXT",
       S2.USERNAME   "HOLDING User",
       S2.OSUSER     "OS User",
       S2.LOGON_TIME "logon time",
       H.SESSION_ID  "Sid",
       P2.SPID       "PID",
       Q2.SQL_TEXT   "SQLTEXT"
  FROM SYS.V_$PROCESS P1,
       SYS.V_$PROCESS P2,
       SYS.V_$SESSION S1,
       SYS.V_$SESSION S2,
       DBA_LOCKS      W,
       DBA_LOCKS      H,
       V$SQL          Q1,
       V$SQL          Q2
 WHERE H.MODE_HELD != 'None'
   AND H.MODE_HELD != 'Null'
   AND W.MODE_REQUESTED != 'None'
   AND W.LOCK_TYPE(+) = H.LOCK_TYPE
   AND W.LOCK_ID1(+) = H.LOCK_ID1
   AND W.LOCK_ID2(+) = H.LOCK_ID2
   AND W.SESSION_ID = S1.SID(+)
   AND H.SESSION_ID = S2.SID(+)
   AND S1.PADDR = P1.ADDR(+)
   AND S2.PADDR = P2.ADDR(+)
   AND S1.SQL_ID = Q1.SQL_ID(+)
   AND S2.SQL_ID = Q2.SQL_ID(+)
 ORDER BY H.SESSION_ID;

2)​​​​​​​Oracle 查询会话与锁及对应sql

复制代码
SELECT A.OWNER 用户,
       A.OBJECT_NAME 表名,
       B.XIDUSN 回滚段号,
       B.XIDSLOT 槽号,
       B.XIDSQN 序列号,
       B.SESSION_ID 锁表SESSION_ID,
       B.ORACLE_USERNAME 锁表用户名,
       DECODE(D.TYPE,
              'XR',
              'NULL',
              'RS',
              'SS(Row-S)',
              'CF',
              'SS(Row-S)',
              'TM',
              'TABLE LOCK',
              'PW',
              'TABLE LOCK',
              'TO',
              'TABLE LOCK',
              'TS',
              'TABLE LOCK',
              'RT',
              'ROW LOCK',
              'TX',
              'ROW LOCK',
              'MR',
              'S(Share)',
              NULL) 锁定方式,
       C.MACHINE 用户组,
       C.TERMINAL 机器名,
       B.OS_USER_NAME 系统用户名,
       B.PROCESS 系统进程ID,
       DECODE(C.STATUS, 'INACTIVE', '不活动', 'ACTIVE', '活动') 活动情况,
       C.SERVER,
       C.SID,
       E.SQL_TEXT,
       C.SERIAL#,
       C.PROGRAM 连接方式,
       C.LOGON_TIME
  FROM ALL_OBJECTS     A,
       V$LOCKED_OBJECT B,
       SYS.GV_$SESSION C,
       V$LOCK          D,
       V$SQLTEXT       E
 WHERE (A.OBJECT_ID = B.OBJECT_ID)
   AND (B.PROCESS = C.PROCESS)
   AND C.SID = D.SID
   AND B.LOCKED_MODE = D.LMODE
   AND C.SQL_ID = E.SQL_ID(+)
 ORDER BY 1, 2;

3)​​​​​​​Oracle 查询持有DDL排他锁的会话过程

复制代码
一、查询持有DDL排他锁的SID
select sid, serial#, paddr, username, osuser, machine, program
  from v$session
 where sid in (select SESSION_ID from dba_ddl_locks where name = 'T_LOG');

二、查询持有DDL排它锁的会话
select sid, serial#, s.sql_id, sql_text, program
  from v$session s, v$sql l
 where sid in (58, 2808, 5121)
   and s.sql_id = l.sql_id;

三、根据上面sid查询spid
select spid, osuser, s.program
  from v$session s, v$process p
 where s.paddr = p.addr
   and s.sid = 2808;

查杀持有DDL排他锁的会话
select 'alter system kill session ''' || s.sid || ',' || s.serial# || ''';',
       paddr,
       username,
       osuser,
       machine,
       program
  from v$session s
 where sid in
       (select SESSION_ID from dba_ddl_locks where name = 'SEQ_WORKFLOW');

4)​​​​​​​Oracle查杀锁会话

复制代码
select s.sid,
       s.machine,
       o.object_name,
       l.oracle_username,
       l.locked_mode,
       'ALTER  SYSTEM  KILL  SESSION  ''' || s.sid || ',  ' || s.serial# ||
       ''';' Command
  from v$locked_object l, v$session s, all_objects o
 where l.session_id = s.sid
   and l.object_id = o.object_id;

5)​​​​​​​Oracle查询锁信息

复制代码
column event format a30  
column sess format a20  
col username for a15 
set linesize 250
set pagesize 999 
break on id1 skip 1
select decode(request, 0, 'Holder:', 'Waiter:') || s.inst_id || ':' ||
       s.sid || ',' || s.serial# sess,
       id1,
       id2,
       lmode,
       request,
       l.type,
       ctime,
       s.username,
       s.sql_id,
       s.event,
       s.service_name
  from gv$lock l, gv$session s
 where (id1, id2, l.type) in
       (select id1, id2, type from gv$lock where request > 0)
   and l.sid = s.sid
   and l.inst_id = s.inst_id
 order by id1, ctime desc, request;

6)​​​​​​​阻塞信息查询

复制代码
SELECT ('节点 ' || a.inst_id || ' session ' || a.sid || ',' || a_s.serial# ||
       ' 阻塞了 节点 ' || b.inst_id || ' session ' || b.sid || ',' ||
       b_s.serial#) blockinfo,
       a.inst_id,
       a_s.sid,
       a_s.schemaname,
       a_s.machine,
       a_s.module,
       a_s.status,
       a.TYPE lock_type,
       a.id1,
       a.id2,
       DECODE(a.lmode,
              0,
              'none',
              1,
              NULL,
              2,
              'row-S (SS)',
              3,
              'row-X (SX)',
              4,
              'share (S)',
              5,
              'S/Row-X (SSX)',
              6,
              'exclusive (X)') lock_mode,
       '后面的为被阻塞信息' blocked_flag,
       b.inst_id blocked_inst_id,
       b_s.sid blocked_sid,
       b.TYPE blocked_lock_type,
       DECODE(b.request,
              0,
              'none',
              1,
              NULL,
              2,
              'row-S (SS)',
              3,
              'row-X (SX)',
              4,
              'share (S)',
              5,
              'S/Row-X (SSX)',
              6,
              'exclusive (X)') blocked_lock_request,
       b_s.schemaname blocked_schemaname,
       b_s.module blocked_module,
       b_s.status blocked_status,
       b_s.sql_id blocked_sql_id,
       obj.owner blocked_owner,
       obj.object_name blocked_object_name,
       obj.object_type blocked_object_type,
       CASE
         WHEN b_s.row_wait_obj# <> -1 THEN
          DBMS_ROWID.rowid_create(1,
                                  obj.data_object_id,
                                  b_s.row_wait_file#,
                                  b_s.row_wait_block#,
                                  b_s.row_wait_row#)
         ELSE
          '-1'
       END blocked_rowid, --被阻塞数据的rowid
       DECODE(obj.object_type,
              'TABLE',
              'select * from ' || obj.owner || '.' || obj.object_name ||
              ' where rowid=''' ||
              DBMS_ROWID.rowid_create(1,
                                      obj.data_object_id,
                                      b_s.row_wait_file#,
                                      b_s.row_wait_block#,
                                      b_s.row_wait_row#) || '''',
              NULL) blocked_data_querysql
  FROM gv$lock     a,
       gv$lock     b,
       gv$session  a_s,
       gv$session  b_s,
       dba_objects obj
 WHERE a.id1 = b.id1
   AND a.id2 = b.id2
   AND a.block > 0 --阻塞了其他人
   AND b.request > 0
   AND ((a.inst_id = b.inst_id AND a.sid <> b.sid) OR
       (a.inst_id <> b.inst_id))
   AND a.sid = a_s.sid
   AND a.inst_id = a_s.inst_id
   AND b.sid = b_s.sid
   AND b.inst_id = b_s.inst_id
   AND b_s.row_wait_obj# = obj.object_id(+)
 ORDER BY a.inst_id, a.sid;

7)​​​​​​​10046 常用等待事件分析

复制代码
alter session set events '10046 trace name context forever,level 12'
或者
oradebug setmypid
oradebug event 10046 trace name context forever,level 12
oradebug tracefile_name
执行SQL语句
alter session set events '10046 trace name context off'
或者
oradebug event 10046 trace name context off

==========
oradebug short_stack
可以采用oradebug或者strace -p跟踪后台或前台进程是否dead或hang住

8)​​​​​​​分析TX锁等待

复制代码
1) 查询异常时刻异常等待
select event, count(*)
  from v$session
 where wait_class != 'Idle'
 group by event
 order by 2;

2) 分析行等待的阻塞者
select sid, sql_id, status, event, seconds_in_wait, state, blocking_session
  from v$session
 where event like 'enq%';

3) 查看阻塞这SID在做什么
select sid,
       last_call_et,
       sql_id,
       status,
       event,
       seconds_in_wait,
       state,
       blocking_session
  from v$session
 where sid = xxxx;

4) 收集数据库hanganalyze和systemstate信息
SQL> oradebug setmypid
Statement processed.
SQL> oradebug hanganalyze 3
Hang Analysis in /oracle/admin/xxdb/udump/xxdb_ora_14136.trc

SQL>
SQL> oradebug dump systemstate 266
Statement processed.
SQL> oradebug tracefile_name
/oracle/admin/xxdb/udump/xxdb_ora_14136.trc

5) 根据SID获得会话的活动历史信息
select to_char(sample_time, 'yyyymmdd hh24:mi:ss') stime,
       session_serial#,
       sql_id,
       session_state,
       event,
       p1,
       p2,
       p3,
       blocking_session
  from v$active_session_history
 where session_id = 315
   and sample_time > sysdate - 2 / 24
 order by 1;

===========可以用如下简单方式查询TX锁情况===========
select sid, sql_id, status, event, seconds_in_wait, state, blocking_session
  from gv$session
 where event like 'enq%';

select sid,
       last_call_et,
       sql_id,
       status,
       event,
       seconds_in_wait,
       state,
       program,
       process,
       blocking_session,
       BLOCKING_SESSION_STATUS
  from gv$session
 where sid = 46;

select to_char(sample_time, 'yyyymmdd hh24:mi:ss') stime,
       session_serial#,
       sql_id,
       session_state,
       event,
       p1,
       p2,
       p3,
       blocking_session
  from gv$active_session_history
 where session_id = 46
   and sample_time > sysdate - 3 / 24
 order by 1;

select object_id from gv$locked_object where session_id=46;

select owner,object_name,object_type from dba_objects where object_id in (100744,100441,100444)分析cursor: pin S wait on X
相关推荐
2301_766283441 小时前
mysql如何实现读写分离的权限分配_不同用户分别赋予权限
jvm·数据库·python
戏舟的嵌入式开源笔记1 小时前
ESP32之初见MQTT
数据库·mongodb
重生之小比特1 小时前
【MySQL 数据库】表的约束
android·数据库·mysql
未来龙皇小蓝1 小时前
SpringBoot API日志系统设计-02:线程池异步化与RabbitMQ解耦
数据库·spring boot·后端·性能优化·rabbitmq·java-rabbitmq
江沉晚呤时1 小时前
用 C# 玩转 Scriban:自动生成报告、代码、文本,效率提升 10 倍
数据库·microsoft·c#·.net
2401_824222691 小时前
HTML函数开发需不需要雷电接口_高速接口实际用途说明【说明】
jvm·数据库·python
一只大袋鼠1 小时前
Spring 事务管理三种实现方式
java·数据库·spring·声明式事务
2401_824222691 小时前
如何用 objectStore.get 根据主键 ID 获取数据库单条数据
jvm·数据库·python
KimiKudo1 小时前
记录数据库迁移中踩过的坑
数据库·数据库迁移·polardb