各位深耕 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