[转帖]consistent read(读一致性)的通俗理解_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3739 | 回复: 0   主题: [转帖]consistent read(读一致性)的通俗理解        下一篇 
kim
注册用户
等级:中校
经验:1729
发帖:222
精华:0
注册:2011-7-21
状态:离线
发送短消息息给kim 加好友    发送短消息息给kim 发消息
发表于: IP:您无权察看 2011-8-1 12:04:14 | [全部帖] [楼主帖] 楼主

首先介绍undo 中的简单结构:

undo header-->transaction table-->undo entries(undo block)-->


undo entries包含的只有一个行改变的col值的undo,并不包含整个行的befor image。

KDO undo record:
KTB Redo op: 0x02 ver: 0x01 op: C uba: 0x02000004.0005.0a
KDO Op code: URP xtype: XA bdba: 0x01c00007 hdba: 0x01c00006
itli: 1 ispac: 0 maxfr: 4863 tabn: 0 slot: 1(0x1) flag: 0x2c
lock: 0 ckix: 0 ncol: 8 nnew: 2 size: -1
col 5: [ 3] c2 20 24
col 7: [ 2] c1 1f
consistent read:


1.读取数据块,如果该块在内存中,则增加一个克隆用于undo

2.读取行头:

tab 0, row 0, @0x1e4c
tl: 44 fb: --H-FL-- lb: 0x1 cc: 8


3.检查lb是否这里有一个itl:

Itl  Xid                      Uba                     Flag
0x01 xid: 0x0003.000.00000010 uba: 0x02000004.0005.09 ----


4.如果有,则读取这个itl的xid,xid=us#.slot#.wrap#

5.读取交易表,如果这个交易已经提交(state=9表示提交)并且有了一scn小于当前查询的system change number,

那么clean out这个块,继续下一个块(如果需要的话)并且返回第一步。(在每一个查询的时候都将产生一个查询

scn,在该scn一下的commit scn都认为对应的交易已经提交)

TRN TBL:
index state cflags wrap#  uel    scn             dba        nub
--------------------------------------------------------------------------
0x00   10   0xc0   0x0010 0x0000 0x0000.00075fec 0x02000004 0x00000001
0x01    9   0x00   0x000f 0x0002 0x0000.00075f77 0x00000000 0x00000000


6.如果没有提交,那么读取最新改变的undo block根据transaction table中显示的dba(该地址为undo entries中最

新改变的块)

7.对比这个块的交易号同交易表中的交易号。如果在undo block中的交易号不等于交易表中的交易号,那么报告错误:

ORA-01555 “Snapshot Too Old.”.
xid: 0x0001.01d.000023a4  seq: 0x2a7 cnt: 0x3f  irb: 0x3f  icl: 0x0   flg: 0x0000
Rec Offset      Rec Offset      Rec Offset      Rec Offset      Rec Offset
---------------------------------------------------------------------------
0x01 0x1f68     0x02 0x1ee8     0x03 0x1e68     0x04 0x1de8     0x05 0x1d68
0x06 0x1cec     0x07 0x1c6c     0x08 0x1bec     0x09 0x1b6c     0x0a 0x1aec
0x0b 0x1a6c     0x0c 0x19f0     0x0d 0x1970     0x0e 0x18f0     0x0f 0x1874
0x10 0x17f8     0x11 0x1778     0x12 0x16f8     0x13 0x1678     0x14 0x15f8


8.如果这个块的交易号等于交易表中的交易号,那么从这个undo entry的头开始,应用改变到块上(该块为在内存中

克隆的块)

If the Transaction IDs are identical, make a copy of the data block in memory.
Starting with the head undo entry, apply the changes to the copied data block.


9.如果这个undo enties的尾巴上有其他的块地址(因为一个交易可能占用了好几个undo块),那么将这个undo block

读到内存中重复分析第七步和第八步。重复7和8步直到首先的record不在包含其他块的地址。

10.当这里不再有前一个数据块的地址,那么这个交易就完全被undo了。(因为undo 块是从最后一个块往前读的,这

是为了保证在��读的时候,最新改变的数据都能在undo中体现)

11.如果这个undo entry包含:

a):包含一个指向前一个交易undo block的地址,读取这个交易的id号在这个前一个交易的undo block头里并读取相应

的交易表entries,返回第五步。record纪录也是从后往前读的,因此有irb指定先读取哪一个。

* Rec #0x1  slt: 0x00  objn: 48636(0x0000bdfc)  objd: 49636  tblspc: 33(0x00000021)
*       Layer:  11 (Row)   opc: 1   rci 0x00
Undo type:  Regular undo   Last buffer split:  No
Temp Object:  No
Tablespace Undo:  No
rdba: 0x00801b7c---------------------------------------->>>>>>  这里有一个指针指向前一个undo block证明


这个undo chain上还有一些undo 块。

*-----------------------------
KDO undo record:
KTB Redo
op: 0x02  ver: 0x01
op: C  uba: 0x00801b7c.02a7.3e
KDO Op code: URP row dependencies Disabled
xtype: XA  bdba: 0x054016c1  hdba: 0x054016b9
itli: 1  ispac: 0  maxfr: 4863
tabn: 0 slot: 85(0x55) flag: 0x2c lock: 0 ckix: 0
ncol: 8 nnew: 5 size: 0
col  3: [ 3]  c1 06 36
col  4: [ 3]  c1 06 36
col  5: [ 1]  30
col  6: [ 2]  c1 02
col  7: [ 6]  c4 02 23 38 39 3d
*-----------------------------
* Rec #0x2  slt: 0x00  objn: 48636(0x0000bdfc)  objd: 49636  tblspc: 33(0x00000021)
*       Layer:  11 (Row)   opc: 1   rci 0x01
Undo type:  Regular undo   Last buffer split:  No
Temp Object:  No
Tablespace Undo:  No
rdba: 0x00000000------------------------------------------>>>>>>这里的dba因为rci决定了它不是这个block的最


后一个record。

这是因为,如果你查询的表有很多个交易在修改,那也需要读取这些所有的这些交易所涉及的undo block,应用到重做

b):如果包含一个ITL纪录,存储这个ITL record到数据块(cr block),然后返回第四步。

 还是关于consistent read。

a.create as select后增加一个表,然后确定当前存放数据的块20没有读到buffer中来:

SQL> select file#,block#,class#,xnc,status,objd,ts# from v$bh where file#>=3 and block#>16;
FILE#     BLOCK#     CLASS#        XNC STATU       OBJD        TS#
---------- ---------- ---------- ---------- ----- ---------- ----------
3         17          8          0 xcur        6308          3
3         18          9          0 xcur        6308          3
3         19          4          0 xcur        6308          3


b.起一个sqlplus 执行select,注意这个时候在buffer中有一个块缓存了:

SQL> select file#,block#,class#,xnc,status,objd,ts# from v$bh where file#>=3 and block#>16;
FILE#     BLOCK#     CLASS#        XNC STATU       OBJD        TS#
---------- ---------- ---------- ---------- ----- ---------- ----------
3         17          8          0 xcur        6308          3
3         18          9          0 xcur        6308          3
3         19          4          0 xcur        6308          3
3         20          1          0 xcur        6308          3


c.在一个session中delete50行没有提交,这是产生一个block buffer:

FILE#     BLOCK#     CLASS#        XNC STATU       OBJD        TS#
---------- ---------- ---------- ---------- ----- ---------- ----------
3         17          8          0 xcur        6308          3
3         18          9          0 xcur        6308          3
3         19          4          0 xcur        6308          3
3         20          1          0 cr          6308          3
3         20          1          0 xcur        6308          3


d.在另外一个session中去执行select动作,有产生了一个block buffer

FILE#     BLOCK#     CLASS#        XNC STATU       OBJD        TS#
---------- ---------- ---------- ---------- ----- ---------- ----------
3         17          8          0 xcur        6308          3
3         18          9          0 xcur        6308          3
3         19          4          0 xcur        6308          3
3         20          1          0 cr          6308          3
3         20          1          0 xcur        6308          3
3         20          1          0 cr          6308          3


e.设想,c步骤和d步骤中的两个块在buffer中肯定不一样,因为在d步骤中产生的cr block肯定应用了

当前那个块的重做,但是结果是,这个两个块除了scn不相同,其他没有区别。原因是这两个块的copy都是来源于

最初的那个在block buffer中的block,因为前面的一个session删除操作没有提交,因此不需要用undo来产生一致性

读,如果我们并没有在实现select,即block没有事先放到buffer中,两个结果应该完全不同:

f.重新启动数据库,检查一下buffer中没有该块:

g.直接启动一个session开始删除操作:

FILE#     BLOCK#     CLASS#        XNC STATU       OBJD        TS#
---------- ---------- ---------- ---------- ----- ---------- ----------
3         17          8          0 xcur        6308          3
3         19          4          0 xcur        6308          3
3         20          1          0 xcur        6308          3
3         20          1          0 cr          6308          3


该块被缓存在buffer中有两个块,状态一个为xcur,一个为cr。猜想:xcur为当前修改产生的块,一个为consistent

block,即为cr块。在该session中dump第20块:

scn: 0x0000.0001f0f7 seq: 0x31 flg: 0x00 tail: 0xf0f70631
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump:  0x00c00014
Object id on Block? Y
seg/obj: 0x18a4  csc: 0x00.1d141  itc: 3  flg: E  typ: 1 - DATA
brn: 0  bdba: 0xc00011 ver: 0x01
inc: 0  exflg: 0
Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.0001c52b
0x02   0x0004.02a.0000004c  0x00802276.0015.05  ----   49  fsc 0x0bf6.00000000
0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000


我们看到dump出来的肯定是状态为xcur的块,因为这里有一个没有提交的tx。

h.我们开始一个新的session,然后dump这个块:

scn: 0x0000.0001f0f7 seq: 0x31 flg: 0x00 tail: 0xf0f70631
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump:  0x00c00014
Object id on Block? Y
seg/obj: 0x18a4  csc: 0x00.1d141  itc: 3  flg: E  typ: 1 - DATA
brn: 0  bdba: 0xc00011 ver: 0x01
inc: 0  exflg: 0
Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.0001c52b
0x02   0x0004.02a.0000004c  0x00802276.0015.05  ----   49  fsc 0x0bf6.00000000
0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000


我们看到这两个块的dump完全一样的。在该session中我们执行一个select操作,然后dump该块,这时我们看到这里

多了一个cr块:

FILE#     BLOCK#     CLASS#        XNC STATU       OBJD        TS#
---------- ---------- ---------- ---------- ----- ---------- ----------
3         17          8          0 xcur        6308          3
3         19          4          0 xcur        6308          3
3         20          1          0 cr          6308          3
3         20          1          0 xcur        6308          3
3         20          1          0 cr          6308          3


dump出来的文件看看:

scn: 0x0000.0001f280 seq: 0x01 flg: 0x00 tail: 0xf2800601
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump:  0x00c00014
Object id on Block? Y
seg/obj: 0x18a4  csc: 0x00.1f280  itc: 3  flg: E  typ: 1 - DATA
brn: 0  bdba: 0xc00011 ver: 0x01
inc: 0  exflg: 0
Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0xffff.000.00000000  0x00000000.0000.00  C---    0  scn 0x0000.0001c52b
0x02   0x0004.02a.0000004c  0x00802276.0015.05  ----   49  fsc 0x0bf6.00000000
0x03   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000


我们看到scn比原来的大,但是ITL还是一样,然后对比一下这两个不同装载下块的dump,还是一样。

因此虽然我们看到了block buffer中有两个cr块,但是无论你从哪个session中去dump这个块,dump的永远是第���次产生

的cr块。oracle为后来的select产生的cr块,不可会dump出来。

i.我将那个session中的delete提交,因为如果不提交则其他的删除动作因为行被锁住而不能执行,然后执行了一个动作

SQL> delete from test1 where obj#<100;
50 rows deleted.


这个时候cr减少了一个同时,dump出来的块已经到了delete被应用得块了,所以这个cr应该将原来最先的delete执行的

时候的那个cr去掉了,因为提交了一个交易在原始的块上,因此同时产生了一个新的cr块。否则如果所有的交易都不提交

那么cr块永远在增加。

另外对于最后的undo entries上是否有ITL存在,我没有模拟出环境,在原始block上有几个ITL但是,这些已经都是提交的

所以,并不是说上面有几个ITL就要回滚几个,而是根据当前块的scn去检查相应的ITL是否提交,如果小于当前的scn,这

些交易回滚又有什么用呢?

因此还是没有知道最后这个undo entries怎么来的ITL。

*-----------------------------
uba: 0x00802274.0015.37 ctl max scn: 0x0000.0001eb16 prv tx scn: 0x0000.0001eb33
KDO undo record:
KTB Redo
op: 0x04  ver: 0x01
op: L  itl: xid:  0x0009.027.0000004b uba: 0x008024d4.0016.37
flg: C---    lkc:  0     scn: 0x0000.0001f04a
KDO Op code: LKR row dependencies Disabled
xtype: XA  bdba: 0x00401f4a  hdba: 0x00401f49
itli: 2  ispac: 0  maxfr: 4863
tabn: 0 slot: 0 to: 0
*-----------------------------
* Rec #0x39  slt: 0x2a  objn: 6308(0x000018a4)  objd: 6308  tblspc: 3(0x00000003)
*       Layer:  11 (Row)   opc: 1   rci 0x00
/////这是这个交易在undo中最后��record,他代表的rci已经指向了最前面。
Undo type:  Regular undo    Begin trans    Last buffer split:  No
Temp Object:  No
Tablespace Undo:  No
rdba: 0x00000000
*-----------------------------
uba: 0x00802274.0015.38 ctl max scn: 0x0000.0001eb33 prv tx scn: 0x0000.0001eb48
KDO undo record:
KTB Redo
op: 0x03  ver: 0x01
op: Z
KDO Op code: IRP row dependencies Disabled
xtype: XA  bdba: 0x00c00014  hdba: 0x00c00013
itli: 2  ispac: 0  maxfr: 4858
tabn: 0 slot: 0(0x0) size/delt: 60
fb: --H-FL-- lb: 0x0  cc: 17
null:


以下是这个undo block的头部。

********************************************************************************
UNDO BLK:
xid: 0x0004.02a.0000004c  seq: 0x15  cnt: 0x44  irb: 0x44  icl: 0x0   flg: 0x0000
Rec Offset      Rec Offset      Rec Offset      Rec Offset      Rec Offset
---------------------------------------------------------------------------
0x01 0x1f74     0x02 0x1f1c     0x03 0x1ee4     0x04 0x1e74     0x05 0x1e3c
0x06 0x1de4     0x07 0x1d8c     0x08 0x1d1c     0x09 0x1ce4     0x0a 0x1c8c


今天终于让我找到了这个undo entries上包含的前一个itl的信息:

首先增加一张表,设置maxtrans=2;oracle默认的maxtrans=255,因为他只用两位来记录。

连续四次对该表进行操作在不同的交易中,导致该块上的itl被重复使用过:

第一次:

Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0008.004.00000315  0x008089c6.0045.16  --U-    9  fsc 0x0000.00153937
0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000


第二次:

Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0008.004.00000315  0x008089c6.0045.16  C---    0  scn 0x0000.00153937
0x02   0x0008.00d.00000315  0x008089c6.0045.19  ----    1  fsc 0x0043.00000000


第三次:

Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x000a.009.0000032b  0x0080387b.0063.2f  ----    1  fsc 0x003a.00000000
0x02   0x0008.00d.00000315  0x008089c6.0045.19  --U-    1  fsc 0x0043.0015397d


第四次:

Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x000a.009.0000032b  0x0080387b.0063.2f  C---    0  scn 0x0000.001539a0
0x02   0x0006.021.00000314  0x00802b38.009c.48  --U-    1  fsc 0x003f.00153a1e


如此,dump出最后的itl中指示的uba地址找到了undo entries中的recored:

********************************************************************************
UNDO BLK:
xid: 0x0006.021.00000314  seq: 0x9c  cnt: 0x48  irb: 0x48  icl: 0x0   flg: 0x0000
...........
*-----------------------------
* Rec #0x48  slt: 0x21  objn: 6379(0x000018eb)  objd: 6379  tblspc: 3(0x00000003)
*       Layer:  11 (Row)   opc: 1   rci 0x00
Undo type:  Regular undo    Begin trans    Last buffer split:  No
Temp Object:  No
Tablespace Undo:  No
rdba: 0x00000000
*-----------------------------
uba: 0x00802b38.009c.47 ctl max scn: 0x0000.0015032c prv tx scn: 0x0000.0015034f
KDO undo record:
KTB Redo
op: 0x04  ver: 0x01
op: L  itl: xid:  0x0008.00d.00000315 uba: 0x008089c6.0045.19
flg: C---    lkc:  0     scn: 0x0000.0015397d
|<--------------------这里就反映了前一个itl------------------------------->|


第三次:

Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x000a.009.0000032b  0x0080387b.0063.2f  ----    1  fsc 0x003a.00000000
0x02   0x0008.00d.00000315  0x008089c6.0045.19  --U-    1  fsc 0x0043.0015397d
|<--------------------0x02------------------------------------------------>|


因此将这个itl应用到cr块上,接着找该地址就可以undo前一个itl,当前先要对比一下scn号,
北京联动北方科技有限公司
到此,consistent reader的这个过程我已经都明白了,而且在实际中显示出来,你明白没有。

KDO Op code: IRP row dependencies Disabled
xtype: XA  bdba: 0x00c0000f  hdba: 0x00c0000b
itli: 2  ispac: 0  maxfr: 4858
tabn: 0 slot: 2(0x2) size/delt: 65
fb: --H-FL-- lb: 0x0  cc: 17
null:
01234567890123456789012345678901234567890123456789012345678901234567890123456789
-----N-----NN-N--
col  0: [ 2]  c1 1f
col  1: [ 2]  c1 1f
col  2: [ 1]  80
col  3: [ 7]  49 5f 43 4f 42 4a 23
col  4: [ 2]  c1 05
col  5: *NULL*
col  6: [ 2]  c1 02
.........


今天差点走入一个误区,我老板说,rbs header中的tx table中的chd和ctl就是记录的关于这个块所有的已经提交的交易。

当时我就表示了怀疑,怎么可能在这里记录,oracle也太傻了。这里当然记录了所有的commit的交易链,那只是说这

个是最老的交易,一个流水号,记录了整个交易链中的顺序,如果重用也是按照最老的开始使用。所以他和consistent

reader用到的undo是无关的。这里也就是biti所说的undo block中也记录了itl的before image。

TRN CTL:: seq: 0x009c chd: 0x001f ctl: 0x0028 inc: 0x00000000 nfb: 0x0001
mgc: 0x8201 xts: 0x0068 flg: 0x0001 opt: 2147483646 (0x7ffffffe)
uba: 0x00802b39.009c.0e scn: 0x0000.001504a5


上面就是transaction header的格式。

dsi原文:

For a transaction ,a transaction slot is allocated as pointed to by CHD.To preserve the data within this
TX slot,the TX commit SCN is saved in KTUXCSCN,the KTUXCUBA field will identify the undo block to protect
the changes to KTUXC,and the CHD and CTL will be updated to reflect the next TX slot to be reused,and
the latest commited slot within the transaction table respectively.thes changes are required to ensure
rollback of the transaction,and read consistency of the TX table header.




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论