作者简介:
----------------------------------------------------
@ 孙显鹏,海天起点oracle技术专家,十年从业经验,
@ 拥有OCP 11G认证,精通oracle内部原理,擅长调优
@ 和解决疑难问题,致力于帮助客户解决生产过程中出
@ 现的问题,提高生产效率。
@ 爱好书法,周易,中医!
@ 微信号:sunyunyi_sun
@ 电 话--18629679269
-----------------------------------------------------
oracle LOCK 分为以下几种:
1:Data Dictionary Lock (DDL)
--row cache locks
--library cache locks and pins
2: Data Manipulation Locks (DML)
--Row locks
--table locks
3: internal locks and latches
4: Distributed locks
5: parallel cacle menagement (PCM) locks
讲解锁首先要说明enqueue,enqueue是一个service由Kernal Serive Enqueue (KSQ)层
提供服务,请求该servies被认为是client层,KSQ通过接口提供enqueue的请求,转换和
释放操作。enqueue是由资源和三个锁链表组成,这个我以前的文档详细讲解过,这里不做过多说明。
enqueue 的6中模式,以及模式之间的兼容性如下:
null
SS = Row Share (lock a row in shared mode)
SX = Row Exclusive (lock a row in exclusive mode)
S = Share (lock the entire table in shared mode)
SSX = Share Row Exclusive (lock the table in shared mode but a row in exclusive)
X = Exclusive (lock the entire table in exclusive mode)
无标题.png (16.24 KB, 下载次数: 7)
2018-2-8 13:44 上传
enqueue分为 client enqueue和managed enqueue
client enqueue:
这也就是我们最常见遇见的enqueue:
1:TM--DML enqueue
2:TX--Transaction enqueue
3: User supplied
至于managed enqueue类型就是你从v$lock中看到的除了上面三个以外的,这部分锁我们不需要太多关心,
比如:BL,CF,CI.....
另外需要注意,enqueue中所有的锁结构都嵌入在SO中,方便进程死掉pmon进行恢复,这个可以通过dump process看到。
enqueue 的唯一号为
TYPE:为两个大写字符,比如TX,TM
ID1:ID2 为四个字节,依据TYPE不同有不同的值。
具体的值你可以从v$lock视图看到,基表为x$ksqeq,
资源信息你可以从v$resource中查询到,基表为x$ksqrs
比如我们常见的DML enqueue:
ID1表示object ID,ID2=0
TX enqueue:
ID1:高字节位表示事物的回滚段号,第字节位表示回滚段的槽号
ID2:表示序列号
很明显ID1-ID2表示事物的XID,这一点非常重要,因为在你分析死锁时,单机环境WFG信息比较容易分析,
rac环境下的WFG信息就会让有些人觉得看不懂,比如下面这个是RAC环境下的死锁WFG信息,
(关于死锁的分析我前面的文章已经详细解释过):
WFG 信息:
Global Wait-For-Graph(WFG) at ddTS[0.17ec] :
BLOCKED 70000140bd013b0 5 wq 2 cvtops x1 [0x1a20004][0x24f37],[TX] [1007-0076-01A3C9DD] 0
BLOCKER 70000140bd01260 5 wq 1 cvtops x8 [0x1a20004][0x24f37],[TX] [1014-014B-000031A9] 0
BLOCKED 70000140bb24858 5 wq 2 cvtops x1 [0x3ea0009][0x8d3c],[TX] [1014-014B-000031A9] 0
BLOCKER 70000140bb24708 5 wq 1 cvtops x8 [0x3ea0009][0x8d3c],[TX] [1007-0076-01A3C9DD] 0
* Cancel deadlock victim lockp xbd013b0
这个我们很明显看到是因为应用设计顺序问题导致两个资源被两个session互斥导致,应该修改应用设计问题。
我这里再啰嗦一次,
BLOCKED 表示被阻塞者,第三列的5就表示阻塞者请求X级锁,0-5,5表示X锁级别最高,TX也只有5级锁。
BLOCKER 表示持有者,同样他持有5级锁,一行和四行是一对互斥了,同样2行和3行也是互斥,就造成死锁。
当然这个是最常见的死锁,死锁的分类较多,比如ITL,BIT INDEX,外键无索引,自制事物等,各自锁的模式不同。
可能看不懂就是因为[TX] [1007-0076-01A3C9DD]信息,这个就代表XID,你往上看trace文件就会发现resource信息,
就是资源信息了,资源是什么东西呢?你要修改一行数据,修改的资源分为两部分,第一是这个表你首先添加SX锁,
防止有人DDL该表,另外你就获取TX锁,TX锁是存储在数据块的ITL信息中,这部分在我以前讲的事物解释中有详细
说明,dump 数据块就可以清楚的看到ITL信息,还有回滚段事物表信息,文章后面会有dump 数据块信息可以参照。
好了,基本理论说完了,我们看看例子:
T表我们只插入一行数据。
session 1(sid:223):
SQL> insert into t values (1,'sun');
1 row created.
SQL> commit;
Commit complete.
SQL> delete t;
1 row deleted.
session 2 (sid:130):
SQL> delete t;
等待锁....
session 3:
SQL> select sid,type,id1,id2,lmode,request from v$lock where type='TX';
SID TY ID1 ID2 LMODE REQUEST
---------- -- ---------- ---------- ---------- ----------
130 TX 65551 1087 0 6
223 TX 65551 1087 6 0
我们看到两个session 修改相同的行,这两个session的ID1和ID2是相同的,为什么?两个不同的session拥有相同的
XID,因为两个session修改的相同的行那么他们的ITL是一样的,XID肯定也是一样的,查询事物表:
SQL> select xid,XIDUSN,XIDSLOT,XIDSQN,STATUS from v$transaction;
XID XIDUSN XIDSLOT XIDSQN STATUS
---------------- ---------- ---------- ---------- ----------------
01000F003F040000 1 15 1087 ACTIVE
只存在一个事物,ID1=65551 二进制为:1 00000000 00001111 ,那么1111=15,前面=1,ID2=1087 对应XID号。
再来看看TM enqueue信息,还是上面的例子:
SQL> select sid,type,id1,id2,lmode,request from v$lock where type='TM';
SID TY ID1 ID2 LMODE REQUEST
---------- -- ---------- ---------- ---------- ----------
130 TM 89008 0 3 0
223 TM 89008 0 3 0
注意SX和SX是兼容的,你看没有锁等待,当然这个你也能从v$lock就可以直接查出object信息就是ID1
select object_name,object_type from dba_objects where object_id=89008
OBJECT_NAME OBJECT_TYPE
-------------------- -------------------
T TABLE
enqueue基本上就说清楚了。
另外关于TX的问题比较复杂了,一个事物可以修改许多行,可以修改不同表,这些信息oracle怎么存储和识别呢?
这个就需要查看undo信息了,下面的例子看看一个事物修改两个表怎么在undo中存储旧的信息的。
session 1:
再建一张表:
SQL> create table T1 (id number);
Table created.
SQL> insert into t1 values (1);
1 row created.
SQL> commit;
select
dbms_rowid.rowid_relative_fno(rowid) ralative_fno,
dbms_rowid.rowid_block_number(rowid) block_number
from t;
RALATIVE_FNO BLOCK_NUMBER
------------ ------------
4 188
select
dbms_rowid.rowid_relative_fno(rowid) ralative_fno,
dbms_rowid.rowid_block_number(rowid) block_number
from t1;
RALATIVE_FNO BLOCK_NUMBER
------------ ------------
4 172
开始事物:这里删除t和t1表,两个表都只有一行数据
SQL> delete t;
1 row deleted.
SQL> delete t1;
1 row deleted.
session 2: 看看enqueue信息
SQL> select sid,type,id1,id2,lmode,request from v$lock where type='TX';
SID TY ID1 ID2 LMODE REQUEST
---------- -- ---------- ---------- ---------- ----------
223 TX 655391 1546 6 0
SQL> select sid,type,id1,id2,lmode,request from v$lock where type='TM';
SID TY ID1 ID2 LMODE REQUEST
---------- -- ---------- ---------- ---------- ----------
223 TM 89008 0 3 0
223 TM 89052 0 3 0
SQL> select xid,XIDUSN,XIDSLOT,XIDSQN,STATUS from v$transaction;
XID XIDUSN XIDSLOT XIDSQN STATUS
---------------- ---------- ---------- ---------- ----------------
0A001F000A060000 10 31 1546 ACTIVE
dump 数据文件中数据块的信息:
alter system dump datafile 4 block 188;
Object id on Block? Y
seg/obj: 0x15bb0 csc: 0x00.1680ff itc: 2 flg: E typ: 1 - DATA
brn: 0 bdba: 0x10000b8 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x000a.016.000005fb 0x00c00115.0199.17 C--- 0 scn 0x0000.001680f6
0x02 0x000a.01f.0000060a 0x00c00c37.019b.09 ---- 1 fsc 0x0008.00000000
bdba: 0x010000bc
data_block_dump,data header at 0x2ae2b73b7a64
===============
tsiz: 0x1f98
hsiz: 0x16
pbl: 0x2ae2b73b7a64
76543210
flag=--------
ntab=1
nrow=2
frre=0
fsbo=0x16
fseo=0x1f52
avsp=0x1f78
tosp=0x1f82
0xe
ti[0] nrow=2 offs=0
0x12
ri[0] sfll=-1
0x14
ri[1] offs=0x1f52
block_row_dump:
tab 0, row 1, @0x1f52
tl: 2 fb: --HDFL-- lb: 0x2
end_of_block_dump
End dump data blocks tsn: 4 file#: 4 minblk 188 maxblk 188
alter system dump datafile 4 block 172;
Block header dump: 0x010000ac
Object id on Block? Y
seg/obj: 0x15bdc csc: 0x00.169657 itc: 2 flg: E typ: 1 - DATA
brn: 0 bdba: 0x10000a8 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0007.021.00000451 0x00c00444.00c2.05 C--- 0 scn 0x0000.0016960c
0x02 0x000a.01f.0000060a 0x00c00c37.019b.0b ---- 1 fsc 0x0007.00000000
bdba: 0x010000ac
data_block_dump,data header at 0x2b16f82c0a64
===============
tsiz: 0x1f98
hsiz: 0x14
pbl: 0x2b16f82c0a64
76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x1f92
avsp=0x1f7b
tosp=0x1f84
0xe
ti[0] nrow=1 offs=0
0x12
ri[0] offs=0x1f92
block_row_dump:
tab 0, row 0, @0x1f92
tl: 2 fb: --HDFL-- lb: 0x2
end_of_block_dump
End dump data blocks tsn: 4 file#: 4 minblk 172 maxblk 172
XID:0x000a.01f.0000060a --一个事物那么两个数据块的XID号都一样
Uba:
0x00c00c37.019b.09
0x00c00c37.019b.0b
注意Uba号的rec是不一样的,一个REC为9,一个REc为 b,在trace文件中可以找到:
select to_number('00c','xxx')/4 from dual;--3
select to_number('00c37','xxxxx') from dual;--3127
alter system dump datafile 3 block 3127;
*-----------------------------
* Rec #0x9 slt: 0x1f objn: 89008(0x00015bb0) objd: 89008 tblspc: 4(0x00000004)
* Layer: 11 (Row) opc: 1 rci 0x00
Undo type: Regular undo Begin trans Last buffer split: No
Temp Object: No
Tablespace Undo: No
rdba: 0x00000000Ext idx: 0
flg2: 0
*-----------------------------
uba: 0x00c00c37.019b.08 ctl max scn: 0x0000.001694e1 prv tx scn: 0x0000.001694e6
txn start scn: scn: 0x0000.0016960c logon user: 86
prev brb: 12586035 prev bcl: 0
KDO undo record:
KTB Redo
op: 0x04 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: L itl: xid: 0x0009.01c.00000510 uba: 0x00c00184.012c.20
flg: C--- lkc: 0 scn: 0x0000.00155cc2
KDO Op code: IRP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x010000bc hdba: 0x010000ba
itli: 2 ispac: 0 maxfr: 4858
tabn: 0 slot: 1(0x1) size/delt: 10
fb: --H-FL-- lb: 0x0 cc: 2
null: --
col 0: [ 2] c1 02
col 1: [ 3] 73 75 6e --t表存在两列。
我在这里解释下上面列的含义,undo块存储的是删除前的旧值,我们转换以下:
t表只有一行数据,值为 1,sun,注意dump函数使用方法,也就是datafile里面就是
这样存储数据的。
SQL> select dump(1,16) from dual;
DUMP(1,16)
-----------------
Typ=2 Len=2: c1,2
select dump('s',16) from dual;
DUMP('S',16)
----------------
Typ=96 Len=1: 73
select dump('u',16) from dual;
DUMP('U',16)
----------------
Typ=96 Len=1: 75
select dump('n',16) from dual;
DUMP('N',16)
----------------
Typ=96 Len=1: 6e
type 2 为number型,type 96为 varcher2,len为长度,后面为具体值。
下面就不转换了。
*-----------------------------
* Rec #0xb slt: 0x1f objn: 89052(0x00015bdc) objd: 89052 tblspc: 4(0x00000004)
* Layer: 11 (Row) opc: 1 rci 0x0a
Undo type: Regular undo Last buffer split: No
Temp Object: No
Tablespace Undo: No
rdba: 0x00000000
*-----------------------------
KDO undo record:
KTB Redo
op: 0x03 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: Z
KDO Op code: IRP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x010000ac hdba: 0x010000aa
itli: 2 ispac: 0 maxfr: 4858
tabn: 0 slot: 0(0x0) size/delt: 6
fb: --H-FL-- lb: 0x0 cc: 1
null: -
col 0: [ 2] c1 02--T1表只有一列。
End dump data blocks tsn: 2 file#: 3 minblk 3127 maxblk 3127
从undo块的内容可以看到,一个事物修改了不同表的行,
oracle将这两个行的undo信息存储在一个undo数据块里,并不是一个undo块
就是数据块的copy并修改其内容的,那是cr块的copy。所以说一个事物就只是对应
一个事物槽号,至于这个槽里面有多少个undo块,那就看你的事物修改了多少行数据,
修改越多那么undo块就越多,当然了该undo段也就越大。从后面undo段头的事物表你就
可以看到事物表最多容纳0x21也就是34个事物。
其实上面undo块的信息和redo信息一样,redo更详细,我们看看redo的dump信息:
alter system dump logfile '/u01/app/oracle/oradata/orainfa/redo02.log'
op: F xid: 0x000a.01f.0000060a uba: 0x00c00c37.019b.09---看到了吧,XID 和 uba信息和上面对应看。
KDO Op code: DRP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x010000bc hdba: 0x010000ba
itli: 2 ispac: 0 maxfr: 4858
tabn: 0 slot: 1(0x1)
CHANGE #2 TYP:0 CLS:35 AFN:3 DBA:0x00c00110--undo段头地址 OBJ:4294967295 SCN:0x0000.00169642 SEQ:1 OP:5.2 ENC:0 RBL:0
ktudh redo: slt: 0x001f sqn: 0x0000060a flg: 0x0012 siz: 180 fbi: 0
uba: 0x00c00c37.019b.09 pxid: 0x0000.000.00000000
CHANGE #3 TYP:0 CLS:36 AFN:3 DBA:0x00c00c37 OBJ:4294967295 SCN:0x0000.00169641 SEQ:1 OP:5.1 ENC:0 RBL:0
ktudb redo: siz: 180 spc: 6982 flg: 0x0012 seq: 0x019b rec: 0x09
xid: 0x000a.01f.0000060a
ktubl redo: slt: 31 rci: 0 opc: 11.1 [objn: 89008 objd: 89008 tsn: 4]
Undo type: Regular undo Begin trans Last buffer split: No
Temp Object: No
Tablespace Undo: No
0x00000000 prev ctl uba: 0x00c00c37.019b.08
prev ctl max cmt scn: 0x0000.001694e1 prev tx cmt scn: 0x0000.001694e6
txn start scn: 0x0000.0016960c logon user: 86 prev brb: 12586035 prev bcl: 0 BuExt idx: 0 flg2: 0
KDO undo record:
KTB Redo
op: 0x04 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: L itl: xid: 0x0009.01c.00000510 uba: 0x00c00184.012c.20
flg: C--- lkc: 0 scn: 0x0000.00155cc2
KDO Op code: IRP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x010000bc hdba: 0x010000ba
itli: 2 ispac: 0 maxfr: 4858
tabn: 0 slot: 1(0x1) size/delt: 10
fb: --H-FL-- lb: 0x0 cc: 2
null: --
col 0: [ 2] c1 02
col 1: [ 3] 73 75 6e --和undo块信息一样,不再啰嗦了
我们dump undo 段头的事物表:
DBA:0x00c00110--undo段头地址
select to_number('00c','xxx')/4 from dual;--3
select to_number('00110','xxxxx') from dual;--272
alter system dump datafile 3 block 272;
TRN TBL:事物表
index state cflags wrap# uel scn dba parent-xid nub stmt_num cmt
------------------------------------------------------------------------------------------------
0x00 9 0x00 0x060a 0x000b 0x0000.0016963e 0x00c00c37 0x0000.000.00000000 0x00000001 0x00000000 1518056636
0x01 9 0x00 0x0609 0x0018 0x0000.0016955f 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056356
0x02 9 0x00 0x060a 0x0005 0x0000.00169534 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056298
0x03 9 0x00 0x0609 0x0011 0x0000.001695a3 0x00c00c34 0x0000.000.00000000 0x00000001 0x00000000 1518056444
0x04 9 0x00 0x060a 0x0012 0x0000.00169546 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056317
0x05 9 0x00 0x060a 0x0015 0x0000.0016953b 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056308
0x06 9 0x00 0x0609 0x001b 0x0000.00169595 0x00c00c34 0x0000.000.00000000 0x00000001 0x00000000 1518056428
0x07 9 0x00 0x0609 0x0002 0x0000.0016952a 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056284
0x08 9 0x00 0x0609 0x0006 0x0000.0016958b 0x00c00c34 0x0000.000.00000000 0x00000001 0x00000000 1518056420
0x09 9 0x00 0x0608 0x0004 0x0000.00169544 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056317
0x0a 9 0x00 0x0609 0x0001 0x0000.0016955d 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056356
0x0b 9 0x00 0x0608 0xffff 0x0000.00169642 0x00c00c37 0x0000.000.00000000 0x00000001 0x00000000 1518056636
0x0c 9 0x00 0x0609 0x000a 0x0000.00169559 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056348
0x0d 9 0x00 0x060a 0x0016 0x0000.001695df 0x00c00c35 0x0000.000.00000000 0x00000001 0x00000000 1518056524
0x0e 9 0x00 0x060b 0x001c 0x0000.00169609 0x00c00c35 0x0000.000.00000000 0x00000001 0x00000000 1518056557
0x0f 9 0x00 0x060b 0x0003 0x0000.0016959e 0x00c00c34 0x0000.000.00000000 0x00000001 0x00000000 1518056436
0x10 9 0x00 0x0609 0x000e 0x0000.00169606 0x00c00c36 0x0000.000.00000000 0x00000001 0x00000000 1518056557
0x11 9 0x00 0x0607 0x001a 0x0000.001695b5 0x00c00c34 0x0000.000.00000000 0x00000001 0x00000000 1518056476
0x12 9 0x00 0x0609 0x0019 0x0000.0016954f 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056332
0x13 9 0x00 0x0609 0x000d 0x0000.001695db 0x00c00c35 0x0000.000.00000000 0x00000001 0x00000000 1518056516
0x14 9 0x00 0x0609 0x0010 0x0000.00169605 0x00c00c37 0x0000.000.00000000 0x00000001 0x00000000 1518056557
0x15 9 0x00 0x0609 0x0009 0x0000.00169542 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056316
0x16 9 0x00 0x0608 0x001d 0x0000.001695e7 0x00c00c35 0x0000.000.00000000 0x00000001 0x00000000 1518056538
0x17 9 0x00 0x0609 0x0021 0x0000.00169517 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056268
0x18 9 0x00 0x0608 0x0008 0x0000.0016956f 0x00c00c34 0x0000.000.00000000 0x00000001 0x00000000 1518056380
0x19 9 0x00 0x0609 0x000c 0x0000.00169554 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056340
0x1a 9 0x00 0x060a 0x0013 0x0000.001695c6 0x00000000 0x0000.000.00000000 0x00000000 0x00000000 1518056492
0x1b 9 0x00 0x0609 0x000f 0x0000.0016959a 0x00c00c34 0x0000.000.00000000 0x00000001 0x00000000 1518056436
0x1c 9 0x00 0x060a 0x0000 0x0000.00169614 0x00c00c37 0x0000.000.00000000 0x00000001 0x00000000 1518056572
0x1d 9 0x00 0x0604 0x0014 0x0000.00169603 0x00c00c37 0x0000.000.00000000 0x00000001 0x00000000 1518056557
0x1e 9 0x00 0x0608 0x0017 0x0000.0016950e 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056252
0x1f 10 0x80 0x060a 0x0002 0x0000.0016960c 0x00c00c37 0x0000.000.00000000 0x00000001 0x00000000 0
0x20 9 0x00 0x0609 0x001e 0x0000.001694fd 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056228
0x21 9 0x00 0x0609 0x0007 0x0000.0016951e 0x00c00c33 0x0000.000.00000000 0x00000001 0x00000000 1518056277
0x1f --这就是我们事物的槽号,SNC=0x0000.0016960c UNDO 块=0x00c00c37 就是我们上面dump的信息
至于oracle的其他锁,enqueue的结构是一模一样的,比如buffer lock的资源结构就是buffer header,lock结构就是buffer handle。
row cache lock 和 library cache locks and pins 你就找他的资源和lock结构就可以完全弄明白每个enqueue的结构,这样你对oracle
的内存架构就会有一个深入的认识,遇到问题思路就比较开阔。另外一定要对oracle的架构有一个层级关系认识这点非常重要。
2018-02-08 今天是儿子的生日,祝愿劭航:生日快乐!学业有成!
孙显鹏