3.1知识点
enqueue是共享内存结构(锁),用于串行化访问数据库资源。参考如下:
WAITEVENT:"enqueue" Reference Note (文档 ID 34566.1)
VIEW:"V$LOCK" Reference Note (文档 ID 29787.1)
在很多trc中,我们会看到enqueue的表现格式为:"TYPE-ID1-ID2",如:
*** 2015-10-1511:15:28.960
ksqgtl *** TM-0001598e-00000000 mode=4 flags=0x401timeout=0 ***
ksqgtl: xcb=0x14b7203f8,ktcdix=2147483647, topxcb=0x14b7203f8
在Oracle 9i的等待事件中,没有把enqueue进行细分,所以如果需要在9i中具体判断是什么enqueue锁,需要通过v$session_wait中enqueue等待事件的P1进行计算。转换方法可以参考:34566.1
SELECT sid,chr(to_char(bitand(p1,-16777216))/16777215)||
chr(to_char(bitand(p1,16711680))/65535) "Lock",
to_char( bitand(p1, 65535) ) "Mode", p1, p2, p3
FROM v$session_wait
WHERE event = 'enqueue';
其实转换的原理很简单,通过查询v$event_name可以得到解释:
SQL> selectname,PARAMETER1, PARAMETER2, PARAMETER3 from v$event_name e where e.NAME ='enqueue';
SQL> selectname,PARAMETER1, PARAMETER2, PARAMETER3 from v$event_name e where e.NAME ='enqueue';

转换的方法是v$session_wait查到的行,把P1RAW进行拆分,如64位系统中,高8位是锁名称,而低8位是请求的锁模式。具体示例如下:
selectsid,seq#,event,p1raw from v$session_wait
where event in('enqueue')
order by p1;

P1RAW是十六进制数,其中4857是锁名称,转成ASCII码为:
SQL> SELECTutl_raw.cast_to_varchar2(replace('4857',' ')) value
FROM dual;
VALUE
------------
HW
所以会话请求HW的排它锁(REQUEST=6,一般发生锁等待事件,都是请求者,所以这里是REQUEST)发生等待。具体什么情况会发生HW的排它锁等待,本篇内容暂不展开讨论。
在Oracle 10g里对enqueue进行了细分,而10g里已经没有enqueue这个等待事件,而是拆分成各个详细的“enq: <TYPE>”类型的等待事件。在10g中'enq: <TYPE>%'类型的等待事件有220多个。
SQL> select* from v$event_name e where e.NAME like 'enq: TX%';

3.2Event
对于想要诊断一个会话在执行过程中需要获取什么锁,可能通过设置10704 Event进行跟踪。
$ oerr ora10704
10704, 00000,"Print out information about what enqueues are being obtained"
//*Cause: When enabled, prints outarguments to calls to ksqcmi and
// ksqlrl and the return values.
// *Action:Level indicates details:
// Level: 1-4: print out basic info for ksqlrl,ksqcmi
// 5-9: also print out stuff incallbacks: ksqlac, ksqlop
// 10+: also print out time for eachline
SQL>oradebug setmypid;
Statementprocessed.
SQL>oradebug event 10704 trace name context forever,level 10;
Statementprocessed.
SQL>lock table t1 in share mode;
Table(s)Locked.
SQL>oradebug tracefile_name;
/oracle/diag/rdbms/test3/test3/trace/test3_ora_37916.trc
locktable获取的enqueue锁如下:
*** 2015-10-1914:55:41.182
ksqgtl *** CU-4e845ff8-00000001 mode=6flags=0x10000 timeout=300 ***
ksqgtl: notransaction
ksqgtl: useexisting ksusetxn DID
ksqgtl:
ksqlkdid: 0001-001E-000030CF
*** 2015-10-1914:55:41.182
***ksudidTrace: ksqgtl
ksusesdi: 0000-0000-00000000
ksusetxn: 0001-001E-000030CF
ksqgtl:RETURNS 0
*** 2015-10-1914:55:41.192
ksqrcl:CU,4e845ff8,1
ksqrcl:returns 0
*** 2015-10-1914:55:41.193
ksqgtl *** TM-000159cc-00000000 mode=4flags=0x401 timeout=21474836 ***
ksqgtl:xcb=0x14b6f8c20, ktcdix=2147483647, topxcb=0x14b6f8c20
ktcipt(topxcb)=0x0
*** 2015-10-1914:55:41.193
ksucti: inittxn DID from session DID
ksqgtl:
ksqlkdid: 0001-001E-000030CF
*** 2015-10-1914:55:41.193
***ksudidTrace: ksqgtl
ktcmydid(): 0001-001E-000030CF
ksusesdi: 0000-0000-00000000
ksusetxn: 0001-001E-000030CF
ksqgtl:RETURNS 0
3.3TX
TX锁的具体概念,可以参考:TX Lock "TransactionEnqueue" (文档 ID 197057.1)。
TX锁是事务enqueue锁,会话持有了TX锁,就表明会话做了事务(如:INSERT, UPDATE, DELETE……),TX锁一般在COMMIT和ROLLBACK后释放。TX锁主要作为排队机制,其它会话修改相同数据时,必须要等到本事务结束。当某个事务的开始时间小于某个查询的开始时间时,TX锁也用于构建数据的一致性读的前景象。
TX锁的ID1和ID2字段说明:
SQL> selecttype, name, id1_tag, id2_tag from v$lock_type l where l.TYPE = 'TX';

TX锁的ID1的高4位就是USN,ID2的低4位是slot,验证如下:
SQL>update t1 set name = 'a' where id = 1517;
1row updated.
SQL> selects.sid,
t.XIDUSN,
t.XIDSLOT,
t.XIDSQN,
l.TYPE,
trunc(l.ID1/power(2,16)) as id1_usn,
bitand(l.ID1,to_number('ffff','xxxx'))as id1_slot,
l.ID2,
l.LMODE,
l.REQUEST
from v$lock l, v$transaction t, v$session s
where s.SADDR = t.SES_ADDR
and s.SID = l.SID
and l.type = 'TX';

TX锁的ID1与ID2与v$transaction上的信息一致,其中USN、SLOT、SQN三个字段组成XID(Transaction ID)。
SQL> selectdbms_rowid.rowid_relative_fno(rowid) as fno,
dbms_rowid.rowid_block_number(rowid) asbno
from t1 where id = 1517;

转储block后,ITL信息如下:
Object id onBlock? Y
seg/obj: 0x159cc csc: 0x00.3863ba itc: 2 flg: - typ: 1 - DATA
fsl: 0 fnx: 0x0 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x000a.003.000020c9 0x00c00120.0d7f.07 ---- 1 fsc 0x0003.00000000
0x02 0x0003.017.00000580 0x00c03d49.03d0.09 C--- 0 scn 0x0000.00365455
USN为回滚段号
SLOT为事务槽号
SQN为序号(该值暂时不解释,请参考相关文档)
SQL> selects.segment_name from dba_rollback_segs s where s.segment_id = 10;
SEGMENT_NAME
------------------------------
_SYSSMU10_1197734989$
SQL> ALTERSYSTEM DUMP UNDO HEADER '_SYSSMU10_1197734989$';
Systemaltered.
转储回滚段头后,检查相应的槽位信息如下,state=10表明该槽位上有个活跃事务:

所以TX锁的ID1和ID2就指到了回滚段的事务槽。每次开始新事务,都需要先分配事务槽,被修改数据块上的ITL的XID信息也指向了相应的事务槽。如果另一个事务修改相同数据块的相同行,发现ITL指向了同一个事务槽,那后来进行的会话就会挂起,等待TX锁。
3.4TM
TM锁比较简单,事务执行INSERT,UPDATE,DELETE,MERGE,SELECT FOR UPDATE,或LOCK TABLE等SQL语句修改一个表时,需要获取'TM'(Table Manipulation)DML队列。持有TM锁,表明事务对相关表有DML操作的权力,并且防止DDL操作与本事务的冲突。假如已经有会话在对表进行DDL操作,如果有其它会话要修改这张表的数据,就首先要申请TM锁,而这时申请TM锁会被挂住,等待事件就是enq: TM - contention。
3.5特殊的锁
3.5.1. DFS lock handle等待
一个会话的等待事件为DFS lock handle,表明这个会话在等待一个全局锁请求的锁句柄。在Oracle RAC中,一些对象级别的State Object会演化为全局锁,如Drop Table,Truncate Table等引起的Table对象变化,另外RAC中sequence创建为ordered类型,那当访问这个sequence时,需要给节点分配全局锁,当访问sequence并发较高时,也会导致DFS lock handle。
SQL> select* from v$event_name e where e.NAME = 'DFS lock handle';

观察DFS lock handle等待事件的定义,其中p1是锁的类型和模式,p2、p3是id1和id2,其实这个等待事件也是与v$lock相关。
例如:以下是DFS lock handle等待信息
SID SEQ# EVENT P1 P2 P3
--- -------------------- ---------- ------ --
767 24410 DFSlock handle 1398145029 696629 0
查看锁的信息如下:
SELECT chr(to_char(bitand(1398145029,-16777216))/16777215)||
chr(to_char(bitand(1398145029,16711680))/65535) "Lock",
to_char( bitand(1398145029, 65535)) "Mode"
FROM dual;
Lock Mode
---- -----
SV 5
这是SV锁是与sequence相关的锁,而p2=696629是这个sequence的object_id。
中国OCM之家
专注数据 共现梦想
QQ群:554334183





